U0 AsmResolve(CCompCtrl *cc, CAsmUnresolvedRef *tmpu, U8 *label, Bool undefined)
{
    CAOTImportExport    *tmpie;
    CAsmUndefHash       *tmpauh;
    I64                  res = Call(tmpu->machine_code);

    if (undefined)
    {
        tmpauh = tmpu->asm_undef_hash;
        while (tmpauh)
        {
            if (tmpauh->hash->type & HTF_UNRESOLVED)
            {
                tmpie = CAlloc(sizeof(CAOTImportExport));
                tmpie->next = tmpauh->hash->ie_list;
                tmpauh->hash->ie_list = tmpie;
                tmpie->rip = tmpu->rip;
                tmpie->aot = cc->aot;
                tmpie->type = tmpu->type;
            }
            tmpauh = tmpauh->next; //Technically, more than one won't work.
        }
    }
    else if (!(tmpu->type & IEF_IMM_NOT_REL))
    {
        res -= tmpu->rel_rip;
        if (tmpu->type == IET_REL_I8  && !(I8_MIN  <= res <= I8_MAX) ||
            tmpu->type == IET_REL_I16 && !(I16_MIN <= res <= I16_MAX))
        {
            PrintErr("Branch out of range at line:%04d %s\n",
                        tmpu->line_num, label);
            LexExcept(cc);
        }
        if (tmpu->U8_avail && tmpu->type > IET_IMM_U8 && -124 <= res <= 123)
            PrintWarn("could use I8 displacement at line:%04d %s %s\n", tmpu->line_num, cc->aotc->last_label, label);
    }
    AOTStoreCodeU8At(cc, tmpu->rip, res.u8[0]);
    if (tmpu->type >= IET_REL_I16)
    {
        AOTStoreCodeU8At(cc, tmpu->rip + 1, res.u8[1]);
        if (tmpu->type >= IET_REL_I32)
        {
            AOTStoreCodeU8At(cc, tmpu->rip + 2, res.u8[2], res.u8[3]);
            if (tmpu->type >= IET_REL_I64)
                AOTStoreCodeU8At(cc, tmpu->rip + 4, res.u8[4], res.u8[5], res.u8[6], res.u8[7]);
        }
    }
}

U0 AOTLocalsResolve(CCompCtrl *cc)
{
    CAOTCtrl            *aotc = cc->aotc;
    CAsmUnresolvedRef   *tmpu = aotc->local_unresolved, *tmpu1;
    CAsmUndefHash       *tmpauh;
    Bool                 undefined;
    U8                  *label = NULL;

    while (tmpu)
    {
        undefined = FALSE;
        tmpu1 = tmpu->next;
        tmpauh = tmpu->asm_undef_hash;
        while (tmpauh)
        {
            if (tmpauh->hash->type & HTF_UNRESOLVED)
            {
                PrintErr("Undefined sym at line:%04d %s %s\n", tmpu->line_num, aotc->last_label, tmpauh->hash->str);
                LexExcept(cc);
            }
            label = tmpauh->hash->str;
            tmpauh = tmpauh->next;
        }
        if (!undefined)
            AsmResolve(cc, tmpu, label, FALSE);
        Free(tmpu->machine_code);
        LinkedListDel(tmpu->asm_undef_hash);
        Free(tmpu);
        tmpu = tmpu1;
    }
    HashTableDel(cc->htc.local_hash_table);
    cc->htc.hash_table_list = cc->htc.local_hash_table = HashTableNew(16);
    cc->htc.local_hash_table->next = cc->htc.global_hash_table;
    aotc->local_unresolved = NULL;
}

U0 AOTGlobalsResolve(CCompCtrl *cc, CAOT *tmpaot)
{
    CAOTCtrl            *aotc = cc->aotc;
    CHashFun            *tmpf;
    CAsmUnresolvedRef   *tmpu = aotc->global_unresolved, *tmpu1;
    I64                  i, j;
    CAOTImportExport    *tmpie, *tmpie1;
    CAsmUndefHash       *tmpauh;
    CHashExport         *tmpex;
    U8                  *label;
    Bool                 undefined;
    CExternUsage        *tmpeu, *tmpeu8;

    while (tmpu)
    {
        label = NULL;
        undefined = FALSE;
        tmpu1 = tmpu->next;
        tmpauh = tmpu->asm_undef_hash;
        while (tmpauh)
        {
            if (tmpauh->hash->type & HTF_UNRESOLVED)
            {
                tmpex = tmpauh->hash;
                if (tmpex->type & HTT_EXPORT_SYS_SYM && tmpex->type & HTF_UNRESOLVED &&
                    !(tmpex->type & HTF_IMPORT) &&
                    (tmpf = HashFind(tmpex->str, cc->htc.hash_table_list, HTT_FUN)) &&
                    !Bt(&tmpf->flags, Cf_EXTERN))
                {
                    tmpex->val = tmpf->exe_addr;
                    tmpex->type &= ~HTF_UNRESOLVED;
                    label = tmpauh->hash->str;
                }
                else
                {
                    if (!(tmpex->type & HTF_IMPORT))
                    {
                        if (cc->htc.local_var_list)
                        {
                            tmpex->type |= HTF_GOTO_LABEL;
                            tmpex->use_count++;
                        }
                        else
                        {
                            PrintErr("Undefined sym at line:%04d %s\n", tmpu->line_num, tmpex->str);
                            LexExcept(cc);
                        }
                    }
                    else if (undefined)
                    {
                        PrintErr("Two imports in same expression "
                                    "not allowed at line:%04d %s\n", tmpu->line_num, tmpex->str);
                        LexExcept(cc);
                    }
                    undefined = TRUE;
                }
            }
            else
                label = tmpauh->hash->str;
            tmpauh = tmpauh->next;
        }
        AsmResolve(cc, tmpu, label, undefined);
        Free(tmpu->machine_code);
        LinkedListDel(tmpu->asm_undef_hash);
        Free(tmpu);
        tmpu = tmpu1;
    }

    for (i = 0; i <= cc->htc.global_hash_table->mask; i++)
    {
        tmpex = cc->htc.global_hash_table->body[i];
        while (tmpex)
        {
            if (tmpex->type & (HTF_IMPORT | HTF_GOTO_LABEL))
            {
                if (tmpex->use_count && (tmpie = tmpex->ie_list))
                {
                    if (tmpex->type & HTF_GOTO_LABEL)
                        tmpie->flags |= IEF_GOTO_LABEL;
                    if (tmpex->import_name)
                        tmpie->str = StrNew(tmpex->import_name);
                    else
                        tmpie->str = StrNew(tmpex->str);
                    do
                    {
                        tmpie1 = tmpie->next;
                        QueueInsert(tmpie, tmpaot->last_ie);
                    }
                    while (tmpie = tmpie1);

                    tmpex->ie_list = NULL;
                }
            }
            else if (tmpex->type & (HTF_EXPORT | HTF_RESOLVE))
            {
                if (tmpex->type & HTF_UNRESOLVED)
                {
                    PrintErr("Undefined sym at %s\n", tmpex->str);
                    LexExcept(cc);
                }
                if (tmpex->type & HTF_RESOLVE)
                {
                    tmpf = tmpex;
                    tmpeu = tmpf->ext_list;
                    while (tmpeu)
                    {
                        tmpeu8 = tmpeu->next;
                        j = tmpf->exe_addr - (tmpeu->rip + 4);
                        AOTStoreCodeU8At(cc, tmpeu->rip, j.u8[0], j.u8[1], j.u8[2], j.u8[3]);
                        Free(tmpeu);
                        tmpeu = tmpeu8;
                    }
                }
                if (tmpex->type & HTF_EXPORT)
                {
                    tmpie = CAlloc(sizeof(CAOTImportExport));
                    tmpie->type = IET_REL32_EXPORT;
                    if (tmpex->type & HTT_FUN)
                        tmpie->rip = tmpf->exe_addr;
                    else if (tmpex->type & HTT_GLOBAL_VAR)
                        tmpie->rip = tmpex(CHashGlobalVar *)->data_addr_rip;
                    else
                        tmpie->rip = tmpex->val;
                    tmpie->aot = cc->aot;
                    if (tmpex->type & HTF_IMM)
                        tmpie->type++;
                    tmpie->str = StrNew(tmpex->str);
                    tmpie->src_link = StrNew(tmpex->src_link);
                    QueueInsert(tmpie, tmpaot->last_ie);
                }
            }
            tmpex = tmpex->next;
        }
    }
}

U0 AsmUnresolvedAdd(CCompCtrl *cc, U8 *machine_code, I64 type, I64 rip, I64 rel_rip,
                CAsmUndefHash *local_asm_undef_hash, CAsmUndefHash *global_asm_undef_hash,
                I64 line_num, Bool U8_avail)
{
    CAsmUnresolvedRef *tmpu = MAlloc(sizeof(CAsmUnresolvedRef));

    tmpu->machine_code  = machine_code;
    tmpu->type          = type;
    tmpu->rip           = rip;
    tmpu->rel_rip       = rel_rip;
    tmpu->aot           = cc->aot;
    tmpu->imm_flag      = FALSE;
    tmpu->line_num      = line_num;
    tmpu->U8_avail      = U8_avail;
    tmpu->str           = NULL;

    if (local_asm_undef_hash)
    {
        tmpu->asm_undef_hash = local_asm_undef_hash;
        tmpu->next = cc->aotc->local_unresolved;
        cc->aotc->local_unresolved = tmpu;
    }
    else
    {
        tmpu->asm_undef_hash = global_asm_undef_hash;
        tmpu->next = cc->aotc->global_unresolved;
        cc->aotc->global_unresolved = tmpu;
        if (global_asm_undef_hash->hash->type & HTF_IMPORT)
        {
            tmpu->str = StrNew(global_asm_undef_hash->hash->str);
            if (global_asm_undef_hash->hash->type & HTF_IMM)
                tmpu->imm_flag = TRUE;
        }
    }
}