I64 InstEntriesCompare(CInst *tmpins1, CInst *tmpins2)
{
        I64 i1, i2, j = 0, res = 0, oc_count1 = tmpins1->opcode_count, oc_count2 = tmpins2->opcode_count;

        if (tmpins1->flags & IEF_STI_LIKE)
                oc_count1--;
        if (tmpins2->flags & IEF_STI_LIKE)
                oc_count2--;
        while (TRUE)
        {
                if (j < oc_count1 && j < oc_count2)
                {
                        if (res = tmpins1->opcode[j] - tmpins2->opcode[j])
                                return res;
                        j++;
                }
                else
                {
                        if (res = oc_count1 - oc_count2)
                                return res;

                        if (tmpins1->flags & IEF_STI_LIKE && tmpins2->flags & IEF_STI_LIKE)
                                return tmpins1->opcode[j] - tmpins2->opcode[j];

                        if (res = tmpins1->flags & IEF_STI_LIKE - tmpins2->flags & IEF_STI_LIKE)
                                return res;

                        if (res = tmpins1->slash_val - tmpins2->slash_val)
                                return res;

                        if (res = tmpins1->flags & IEF_OP_SIZE32 - tmpins2->flags & IEF_OP_SIZE32)
                                return res;

                        i1 = Bt(&uasm.ins64_arg_mask, tmpins1->arg1) || Bt(&uasm.ins64_arg_mask, tmpins1->arg2);
                        i2 = Bt(&uasm.ins64_arg_mask, tmpins2->arg1) || Bt(&uasm.ins64_arg_mask, tmpins2->arg2);
                        if (res = i1 - i2)
                                return res;

                        if (res = tmpins1->flags & IEF_48_REX - tmpins2->flags & IEF_48_REX)
                                return res;

                        i1 = tmpins1->arg2 == ARGT_IMM64 || tmpins1->arg2 == ARGT_UIMM64;
                        i2 = tmpins2->arg2 == ARGT_IMM64 || tmpins2->arg2 == ARGT_UIMM64;
                        return i1 - i2;
                }
        }
}

/*
U0 DumpUAsmIns(CInst *tmpins)
{
        CHashOpcode *tmpo = tmpins(U8 *) - tmpins->ins_entry_num * sizeof(CInst) - offset(CHashOpcode.ins);
        "%10s:%02d,%02d SV:%02d\n", tmpo->str, tmpins->arg1, tmpins->arg2, tmpins->slash_val;
}
U0 DumpUAsmTables()
{
        I64 k;
        "16/32 Bit Table\n";
        for (k = 0; k < uasm.table_16_32_entries; k++)
                DumpUAsmIns(uasm.table_16_32[k]);
        "\n\n\n\n64 Bit Table\n";
        for (k = 0; k < uasm.table_64_entries; k++)
                DumpUAsmIns(uasm.table_64[k]);
}
*/

CInst *InstEntryFind(U8 *rip, I64 opsize, I64 seg_size)
{//Binary Search
        I64              i, j, n, m, k, arg1, arg2, o1, o2, oc_count;
        CInst   *tmpins, **table;

        i = 0;
        if (seg_size == 64)
        {
                table = uasm.table_64;
                j = uasm.table_64_entries - 1;
        }
        else
        {
                table = uasm.table_16_32;
                j = uasm.table_16_32_entries - 1;
        }
        while (TRUE)
        {
                k = (i + j) >> 1;  //binary search
                tmpins = table[k];
//DumpUAsmIns(tmpins);
                m = 0;
                n = 0;
                while (TRUE)
                { //ief_compare_start
                        arg1 = tmpins->arg1;
                        arg2 = tmpins->arg2;
                        oc_count = tmpins->opcode_count;
                        if (tmpins->flags & IEF_STI_LIKE)
                                oc_count--;
                        if (n < oc_count)
                        {
                                o1 = rip[n];
                                if (n == tmpins->opcode_count - 1 && tmpins->flags & IEF_PLUS_OPCODE)
                                        o1 &= -8;
                                o2 = tmpins->opcode[n++];
                                if (m = o1 - o2)
                                        goto ief_compare_done;
                        }
                        else
                                switch [tmpins->uasm_slash_val]
                                {
                                        case 0...7:
                                                if (!(m = rip[n] >> 3 & 7 - tmpins->slash_val))
                                                {
                                                        if ((Bt(&uasm.mem_arg_mask, arg1) || Bt(&uasm.mem_arg_mask, arg2)) && rip[n] & 0xC0 == 0xC0)
                                                        {
                                                                m = 1;
                                                                goto ief_compare_done;
                                                        }
                                                        if (opsize == 16)
                                                        {
                                                                if (tmpins->flags & IEF_OP_SIZE32)
                                                                {
                                                                        m = -1;
                                                                        goto ief_compare_done;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                if (tmpins->flags & IEF_OP_SIZE16)
                                                                {
                                                                        m = 1;
                                                                        goto ief_compare_done;
                                                                }
                                                        }
                                                        if (opsize == 64 || arg1 == ARGT_M64 || arg2 == ARGT_M64)
                                                        {
                                                                if (!Bt(&uasm.ins64_arg_mask, arg1) && !Bt(&uasm.ins64_arg_mask, arg2) &&
                                                                                !(tmpins->flags & IEF_48_REX))
                                                                        m = 1;
                                                        }
                                                        else
                                                        {
                                                                if (Bt(&uasm.ins64_arg_mask, arg1) || Bt(&uasm.ins64_arg_mask, arg2) ||
                                                                                tmpins->flags & IEF_48_REX)
                                                                        m = -1;
                                                        }
                                                }
                                                else if ((Bt(&uasm.mem_arg_mask, arg1) || Bt(&uasm.mem_arg_mask, arg2)) && rip[n] & 0xC0 == 0xC0)
                                                        m = 1;
                                                goto ief_compare_done;

                                        case SV_I_REG:
                                                m = rip[n] >> 3 - tmpins->opcode[tmpins->opcode_count - 1] >> 3;
                                                goto ief_compare_done;

                                        case SV_STI_LIKE:
                                                if (!(m = rip[n] >> 3 - tmpins->opcode[tmpins->opcode_count - 1] >> 3))
                                                        m = rip[n] - tmpins->opcode[tmpins->opcode_count - 1];
                                                goto ief_compare_done;

                                        case SV_R_REG:
                                        case SV_NONE:
                                                m = 0;
                                                if (opsize == 16)
                                                {
                                                        if (tmpins->flags & IEF_OP_SIZE32)
                                                        {
                                                                m = -1;
                                                                goto ief_compare_done;
                                                        }
                                                }
                                                else
                                                {
                                                        if (tmpins->flags & IEF_OP_SIZE16)
                                                        {
                                                                m = 1;
                                                                goto ief_compare_done;
                                                        }
                                                }
                                                if (opsize == 64 || arg1 == ARGT_M64 || arg2 == ARGT_M64)
                                                {
                                                        if (!Bt(&uasm.ins64_arg_mask, arg1) && !Bt(&uasm.ins64_arg_mask, arg2) &&
                                                                        !(tmpins->flags & IEF_48_REX) && !(arg2 == ARGT_NONE &&
                                                                        (ARGT_UIMM8 <= arg1 <= ARGT_UIMM64 || ARGT_IMM8 <= arg1 <= ARGT_IMM64)))
                                                                m = 1;
                                                        else if (tmpins->arg2 == ARGT_IMM64 || tmpins->arg2 == ARGT_UIMM64)
                                                        {
                                                                if (arg2 != ARGT_IMM64 && arg2 != ARGT_UIMM64)
                                                                        m = 1;
                                                        }
                                                        else if (arg2 == ARGT_IMM64 || arg2 == ARGT_UIMM64)
                                                                m = -1;
                                                }
                                                else
                                                {
                                                        if (Bt(&uasm.ins64_arg_mask, arg1) || Bt(&uasm.ins64_arg_mask, arg2) ||
                                                                        tmpins->flags & IEF_48_REX)
                                                                m = -1;
                                                }
                                                goto ief_compare_done;
                                }
                }
ief_compare_done:
                if (m > 0)
                {
                        if (k == i)
                        {
                                k = j;
                                break;
                        }
                        else
                                i = k;
                }
                else if (m < 0)
                {
                        if (k - i <= 1)
                        {
                                k = i;
                                break;
                        }
                        else
                                j = k;
                }
                else
                        break;
        }
        return table[k];
}

U0 UAsmHashLoad()
{
        CHashOpcode     *tmph;
        CInst           *tmpins;
        I64                      i, j1, j2, k;

        uasm.ins64_arg_mask = 0x0880888880 + 1 << ARGT_ST0 + 1 << ARGT_STI;
        uasm.signed_arg_mask = 1 << ARGT_REL8 + 1 << ARGT_REL16 + 1 << ARGT_REL32+
                                                   1 << ARGT_IMM8 + 1 << ARGT_IMM16 + 1 << ARGT_IMM32 + 1 << ARGT_IMM64;
        uasm.mem_arg_mask = 1 << ARGT_M8 + 1 << ARGT_M16 + 1 << ARGT_M32 + 1 << ARGT_M64;

        uasm.table_16_32_entries = uasm.table_64_entries = 0;
        for (i = 0; i <= cmp.asm_hash->mask; i++)
        {
                tmph = cmp.asm_hash->body[i];
                while (tmph)
                {
                        if (tmph->type == HTT_OPCODE && !(tmph->oc_flags & OCF_ALIAS))
                        {
                                tmpins = &tmph->ins;
                                for (k = 0; k < tmph->inst_entry_count; k++)
                                {
                                        uasm.table_16_32_entries++;
                                        if (!(tmpins->flags & IEF_NOT_IN_64_BIT))
                                                uasm.table_64_entries++;
                                        tmpins++;
                                }
                        }
                        tmph = tmph->next;
                }
        }

        j1 = j2 = 0;
        uasm.table_16_32 = MAlloc(uasm.table_16_32_entries * sizeof(U8 *));
        uasm.table_64    = MAlloc(uasm.table_64_entries    * sizeof(U8 *));
        for (i = 0; i <= cmp.asm_hash->mask; i++)
        {
                tmph = cmp.asm_hash->body[i];
                while (tmph)
                {
                        if (tmph->type == HTT_OPCODE && !(tmph->oc_flags & OCF_ALIAS))
                        {
                                tmpins = &tmph->ins;
                                for (k = 0; k < tmph->inst_entry_count; k++)
                                {
                                        uasm.table_16_32[j1++] = tmpins;
                                        if (!(tmpins->flags & IEF_NOT_IN_64_BIT))
                                                uasm.table_64[j2++] = tmpins;
                                        tmpins++;
                                }
                        }
                        tmph = tmph->next;
                }
        }
        QuickSortI64(uasm.table_16_32, uasm.table_16_32_entries,  &InstEntriesCompare);
        QuickSortI64(uasm.table_64       , uasm.table_64_entries        , &InstEntriesCompare);
}

U0 Ui(U8 *buf, U8 **_rip, I64 seg_size=64, I64 *_jmp_dst=NULL, Bool just_ins=FALSE)
{//Unassembles one inst
        I64                      i, disp, imm, opsize, opadd, arg1, arg2, reloced_arg1, reloced_arg2,
                                 arg1_size = 0, arg2_size = 0, reloced_arg1_size, reloced_arg2_size,
                                 ModrM = -1, SIB = -1, scale, r1, r2, Mod = -1, RM1 = -1, RM2 = -1, REX = -1, REX_r = 0, REX_x = 0, REX_b = 0;
        Bool             cont;
        CInst           *tmpins, *tmpins2;
        CHashOpcode     *tmpo;
        U8                      *rip = *_rip, *ptr, *reloced_arg1_st, *reloced_arg2_st, *bin_data_area1, *bin_data_area2,
                                 line1[512], line2[512], buf2[512], arg1_st[512], arg2_st[512], seg_overrides[32];

        if (_jmp_dst)
                *_jmp_dst = -1;
        if (seg_size == 16)
        {
                opsize = 16;
                opadd = 16;
        }
        else if (seg_size == 32)
        {
                opsize = 32;
                opadd = 32;
        }
        else
        {
                opsize = 32;
                opadd = 64;
        }
        *arg1_st = 0;
        *arg2_st = 0;
        if (!IsRaw && PutSrcLink(rip, 1, line1))
                CatPrint(line1, "\n");
        else
                *line1 = 0;

        StrPrint(line1 + StrLen(line1), "%24tp ", rip);
        bin_data_area1 = line1 + StrLen(line1);
        for (i = 0; i < 6; i++)
                CatPrint(line1, "%02X", rip[i]);
        CatPrint(line1, " ");

        StrPrint(line2, "%24tp ", rip + 6);
        bin_data_area2 = line2 + StrLen(line2);
        for (i = 6; i < 12; i++)
                CatPrint(line2, "%02X", rip[i]);

        *seg_overrides = 0;
        cont = TRUE;
        while (TRUE)
        {
                switch (*rip)
                {
                        case 0x2E:
                                if (StrLen(seg_overrides) < 24)
                                        CatPrint(seg_overrides, "CS:");
                                break;

                        case 0x36:
                                if (StrLen(seg_overrides) < 24)
                                        CatPrint(seg_overrides, "SS:");
                                break;

                        case 0x3E:
                                if (StrLen(seg_overrides) < 24)
                                        CatPrint(seg_overrides, "DS:");
                                break;

                        case 0x26:
                                if (StrLen(seg_overrides) < 24)
                                        CatPrint(seg_overrides, "ES:");
                                break;

                        case 0x64:
                                if (StrLen(seg_overrides) < 24)
                                        CatPrint(seg_overrides, "FS:");
                                break;

                        case 0x65:
                                if (StrLen(seg_overrides) < 24)
                                        CatPrint(seg_overrides, "GS:");
                                break;

                        case OC_OP_SIZE_PREFIX:
                                if (opsize == 16)
                                        opsize = 32;
                                else
                                        opsize = 16;
                                break;

                        case OC_ADDR_SIZE_PREFIX:
                                if (opadd == 16)
                                        opadd = 32;
                                else
                                        opadd = 16;
                                break;

                        case 0x40...0x4F:
                                if (seg_size == 64)
                                {
                                        REX = *rip;
                                        if (REX >= 0x48)
                                                opsize = 64;
                                        REX_b = Bt(&REX, 0) << 3;
                                        REX_x = Bt(&REX, 1) << 3;
                                        REX_r = Bt(&REX, 2) << 3;
                                        break;
                                } //Fall thru if !64
                        default:
                                cont = FALSE;
                }
                if (cont)
                        rip++;
                else
                        break;
        }

        tmpins = InstEntryFind(rip, opsize, seg_size);
        if (opsize == 32 && seg_size == 64)
        {
                tmpins2 = InstEntryFind(rip, 64, seg_size);
                if (tmpins2 != tmpins && tmpins2->flags & IEF_REX_ONLY_R8_R15 || tmpins2->flags & IEF_REX_XOR_LIKE &&
                                rip[1] >> 3 & 7 == rip[1] & 7)
                        tmpins = tmpins2;
        }

        rip += tmpins->opcode_count;
        tmpo = tmpins(U8 *) - tmpins->ins_entry_num * sizeof(CInst)
        -offset(CHashOpcode.ins);
        if (just_ins)
                *line1 = 0;
        CatPrint(line1, tmpo->str);

        arg1 = tmpins->arg1;
        arg2 = tmpins->arg2;

        if (arg1_size = tmpins->size1)
        {
                if (Bt(&uasm.signed_arg_mask, arg1))
                        CatPrint(arg1_st, "I%d ", arg1_size);
                else
                        CatPrint(arg1_st, "U%d ", arg1_size);
        }

        if (arg2_size = tmpins->size2)
        {
                if (Bt(&uasm.signed_arg_mask, arg2))
                        CatPrint(arg2_st, "I%d ", arg2_size);
                else
                        CatPrint(arg2_st, "U%d ", arg2_size);
        }

        if (tmpins->flags & IEF_PLUS_OPCODE)
        {
                rip--;
                RM1 = *rip++ - tmpins->opcode[tmpins->opcode_count - 1] + REX_b;
                ptr = NULL;
                if (ARGT_R8 <= arg1 <= ARGT_R64)
                {
                        if (arg1_size == 8)
                        {
                                if (REX != -1)
                                        ptr = "ST_U8_REX_REGS";
                                else
                                        ptr = "ST_U8_REGS";
                        }
                        else if (arg1_size == 16)
                                ptr = "ST_U16_REGS";
                        else if (arg1_size == 32)
                                ptr="ST_U32_REGS";
                        else if (arg1_size == 64)
                                ptr = "ST_U64_REGS";
                        if (ptr)
                                CatPrint(arg1_st, "%Z", RM1, ptr);
                }
                else
                {
                        if (arg2_size == 8)
                        {
                                if (REX != -1)
                                        ptr = "ST_U8_REX_REGS";
                                else
                                        ptr = "ST_U8_REGS";
                        }
                        else if (arg2_size == 16)
                                ptr = "ST_U16_REGS";
                        else if (arg2_size == 32)
                                ptr = "ST_U32_REGS";
                        else if (arg2_size == 64)
                                ptr = "ST_U64_REGS";
                        if (ptr)
                                CatPrint(arg2_st, "%Z", RM1, ptr);
                }
        }

        if (ARGT_RM8 <= arg1 <= ARGT_RM64 || ARGT_M8 <= arg1 <= ARGT_M64 ||
                ARGT_RM8 <= arg2 <= ARGT_RM64 || ARGT_M8 <= arg2 <= ARGT_M64)
        {
                if (ARGT_RM8 <= arg2 <= ARGT_RM64 || ARGT_M8 <= arg2 <= ARGT_M64)
                {
                        reloced_arg1 = arg2;
                        reloced_arg2 = arg1;
                        reloced_arg1_size = arg2_size;
                        reloced_arg2_size = arg1_size;
                        reloced_arg1_st = arg2_st;
                        reloced_arg2_st = arg1_st;
                }
                else
                {
                        reloced_arg1 = arg1;
                        reloced_arg2 = arg2;
                        reloced_arg1_size = arg1_size;
                        reloced_arg2_size = arg2_size;
                        reloced_arg1_st = arg1_st;
                        reloced_arg2_st = arg2_st;
                }

                CatPrint(reloced_arg1_st, seg_overrides);
                ModrM = *rip++;
                Mod = ModrM >> 6 & 3;
                RM1 = ModrM & 7 + REX_b;
                RM2 = ModrM >> 3 & 7 + REX_r;
                if (Mod < 3 && RM1 & 7 == 4)
                        SIB = *rip++;
                if (Mod == 1) {
                        disp = *rip(U8 *)++;
                        CatPrint(reloced_arg1_st, "%02X", disp);
                }
                else if (Mod == 2)
                {
                        disp = *rip(U32 *)++;
                        CatPrint(reloced_arg1_st, "%08X", disp);
                }
                if (tmpins->slash_val < 8)
                        RM2 = -1;
                else
                {
                        ptr = NULL;
                        if (reloced_arg2 == ARGT_SREG)
                        {
                                if (RM2 <= 5)
                                        ptr = "ST_SEG_REGS";
                        }
                        else if (!(ARGT_IMM8 <= reloced_arg2 <= ARGT_IMM64) && !(ARGT_UIMM8 <= reloced_arg2 <= ARGT_UIMM64))
                        {
                                if (reloced_arg2_size == 8)
                                {
                                        if (REX != -1)
                                                ptr = "ST_U8_REX_REGS";
                                        else
                                                ptr = "ST_U8_REGS";
                                }
                                else if (reloced_arg2_size == 16)
                                        ptr = "ST_U16_REGS";
                                else if (reloced_arg2_size == 32)
                                        ptr = "ST_U32_REGS";
                                else if (reloced_arg2_size == 64)
                                        ptr = "ST_U64_REGS";
                        }
                        if (ptr)
                                CatPrint(reloced_arg2_st, "%Z", RM2, ptr);
                }
                if (RM1 & 7 == 5 && !Mod)
                {
                        disp = *rip(I32 *)++;
                        if (seg_size == 64)
                        {
                                disp += rip;
                                if (reloced_arg2 == ARGT_IMM8 || reloced_arg2 == ARGT_UIMM8)
                                        disp++;
                                else if (reloced_arg2 == ARGT_IMM16 || reloced_arg2 == ARGT_UIMM16)
                                        disp += 2;
                                else if (reloced_arg2 == ARGT_IMM32 || reloced_arg2 == ARGT_UIMM32)
                                        disp += 4;
                                else if (reloced_arg2 == ARGT_IMM64 || reloced_arg2 == ARGT_UIMM64)
                                        disp += 8;
                        }
                        CatPrint(reloced_arg1_st, "[%X]", disp);
                        RM1 = -1;
                }
                else
                {
                        if (Mod < 3)
                        {
                                if (RM1 & 7 == 4)
                                {
                                        RM1 = -1;
                                        r1 = SIB & 7 + REX_b;
                                        r2 = SIB >> 3 & 7 + REX_x;
                                        scale = SIB >> 6 & 3;
                                        if (scale == 3)
                                                scale = 8;
                                        else if (scale == 2)
                                                scale = 4;
                                        else if (scale == 1)
                                                scale = 2;
                                        else
                                                scale = 1;
                                        if (seg_size == 64)
                                                ptr = "ST_U64_REGS";
                                        else
                                                ptr = "ST_U32_REGS";
                                        if (r1 == REG_RBP && !Mod)
                                        {
                                                disp = *rip(U32 *)++;
                                                CatPrint(reloced_arg1_st, "%08X[%Z*%d]", disp, r2, ptr, scale);
                                        }
                                        else if (r2 == 4)
                                                CatPrint(reloced_arg1_st, "[%Z]", r1, ptr);
                                        else
                                                CatPrint(reloced_arg1_st, "[%Z+%Z*%d]", r1, ptr, r2, ptr, scale);
                                }
                                else
                                {
                                        if (opadd == 16)
                                                ptr = "ST_U16_REGS";
                                        else if (opadd == 32)
                                                ptr = "ST_U32_REGS";
                                        else
                                                ptr = "ST_U64_REGS";
                                        CatPrint(reloced_arg1_st, "[%Z]", RM1, ptr);
                                }
                        }
                        else
                        {
                                ptr = NULL;
                                if (reloced_arg1_size == 8)
                                {
                                        if (REX != -1)
                                                ptr = "ST_U8_REX_REGS";
                                        else
                                                ptr = "ST_U8_REGS";
                                }
                                else if (reloced_arg1_size == 16)
                                        ptr = "ST_U16_REGS";
                                else if (reloced_arg1_size == 32)
                                        ptr = "ST_U32_REGS";
                                else if (reloced_arg1_size == 64)
                                        ptr = "ST_U64_REGS";
                                if (ptr)
                                        CatPrint(reloced_arg1_st, DefineSub(RM1, ptr));
                        }
                }
        }

        switch (arg1)
        {
                case ARGT_IMM8:
                case ARGT_UIMM8:
                        imm = *rip(U8 *)++;
                        CatPrint(arg1_st, "%02X", imm);
                        if (tmpins->opcode[0] == 0xCD && (ptr = DefineSub(imm, "ST_INT_NAMES")))
                                CatPrint(arg1_st, " %s", ptr);
                        break;

                case ARGT_IMM16:
                case ARGT_UIMM16:
                        CatPrint(arg1_st, "%04X", *rip(U16 *)++);
                        break;

                case ARGT_IMM32:
                case ARGT_UIMM32:
                        CatPrint(arg1_st, "%08X", *rip(U32 *)++);
                        break;

                case ARGT_IMM64:
                case ARGT_UIMM64:
                        CatPrint(arg1_st, "%016X", *rip(I64 *)++);
                        break;
                start:
                        case ARGT_REL8:
                                disp = *rip(I8 *)++;
                                break;

                        case ARGT_REL16:
                                disp = *rip(I16 *)++;
                                break;

                        case ARGT_REL32:
                                disp = *rip(I32 *)++;
                                break;
                end:
                        disp += rip;
                        if (IsDebugMode)
                                CatPrint(arg1_st, "%p ", disp);
                        else if (PutSrcLink(disp, 512, buf2))
                                CatPrint(arg1_st, "%s ", buf2);
                        else
                                CatPrint(arg1_st, "%P ", disp);
                        if (_jmp_dst)
                                *_jmp_dst = disp;
                        break;

                case ARGT_MOFFS8...ARGT_MOFFS64:
                        CatPrint(arg1_st, seg_overrides);
                        if (arg1_size == 8)
                                disp = *rip(U8 *)++;
                        else if (opadd == 16)
                                disp = *rip(U16 *)++;
                        else
                                disp = *rip(U32 *)++;
                        CatPrint(arg1_st, "[%X]",disp);
                        break;

                case ARGT_AL ... ARGT_DX:
                case ARGT_SS ... ARGT_ST0:
                        CatPrint(arg1_st, "%z", arg1 - ARGT_AL, "AL\0AX\0EAX\0RAX\0CL\0DX\0 \0 \0SS\0DS\0ES\0FS\0GS\0CS\0ST0\0");
                        break;

                case ARGT_STI:
                        rip--;
                        CatPrint(arg1_st, "%Z", *rip++ - tmpins->opcode[tmpins->opcode_count - 1], "ST_FSTACK_REGS");
                        break;
        }

        switch (arg2)
        {
                case ARGT_IMM8:
                case ARGT_UIMM8:
                        CatPrint(arg2_st, "%02X", *rip(U8 *)++);
                        break;

                case ARGT_IMM16:
                case ARGT_UIMM16:
                        CatPrint(arg2_st, "%04X", *rip(U16 *)++);
                        break;

                case ARGT_IMM32:
                case ARGT_UIMM32:
                        CatPrint(arg2_st, "%08X", *rip(U32 *)++);
                        break;

                case ARGT_IMM64:
                case ARGT_UIMM64:
                        CatPrint(arg2_st, "%016X", *rip(I64 *)++);
                        break;

                case ARGT_MOFFS8...ARGT_MOFFS64:
                        CatPrint(arg2_st, seg_overrides);
                        if (arg2_size == 8)
                                disp = *rip(U8 *)++;
                        else if (opadd == 16)
                                disp = *rip(U16 *)++;
                        else
                                disp = *rip(U32 *)++;
                        CatPrint(arg2_st, "[%X]", disp);
                        break;

                case ARGT_AL ... ARGT_DX:
                case ARGT_SS ... ARGT_ST0:
                        CatPrint(arg2_st, "%z",arg2 - ARGT_AL, "AL\0AX\0EAX\0RAX\0CL\0DX\0 \0 \0SS\0DS\0ES\0FS\0GS\0CS\0ST0\0");
                        break;

                case ARGT_STI:
                        rip--;
                        CatPrint(arg2_st, "%Z", *rip++ - tmpins->opcode[tmpins->opcode_count - 1], "ST_FSTACK_REGS");
                        break;
        }
        if (tmpins->flags & IEF_ENDING_ZERO)
                rip++;

        if (*arg1_st)
                CatPrint(line1, "\t%s", arg1_st);
        if (*arg2_st)
                CatPrint(line1, ",%s", arg2_st);
        CatPrint(line1, "\n");
        CatPrint(line2, "\n");
        if (!just_ins)
        {
                for (i = rip - (*_rip)(I64); i < 6; i++)
                {
                        bin_data_area1[i << 1]     = CH_SPACE;
                        bin_data_area1[i << 1 + 1] = CH_SPACE;
                }
                for (i = rip - (*_rip)(I64); i < 12; i++)
                {
                        bin_data_area2[(i - 6) << 1]     = CH_SPACE;
                        bin_data_area2[(i - 6) << 1 + 1] = CH_SPACE;
                }
        }
        StrCopy(buf, line1);
        if (!just_ins && rip - (*_rip)(I64) > 6)
                CatPrint(buf, line2);
        *_rip = rip;
}

U8 *U(U8 *rip, I64 count=20, I64 seg_size=64)
{//Unassembles a num of insts.
        I64 i;
        U8  buf[1024];

        if (seg_size == 16)
                PrintWarn("16-bit unassembly is not well supported.\n");
        "$HL,1$";
        for (i = 0; i < count; i++)
        {
                Ui(buf, &rip, seg_size);
                "%s", buf;
        }
        "$HL,0$";

        return rip;
}

I64 Un(U8 *rip, I64 count=0x80, I64 seg_size=64)
{//Unassembles a num of bytes
        I64 i = 0;
        U8  buf[1024], *end_rip = rip(I64) + count;

        if (seg_size == 16)
                PrintWarn("16-bit unassembly is not well supported.\n");
        "$HL,1$";
        while (rip < end_rip)
        {
                Ui(buf, &rip, seg_size);
                "%s", buf;
                i++;
        }
        "$HL,0$";

        return i;
}