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;
                }
        }
}