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 instruction
    I64          i, disp, imm, opsize, opadd, arg1, arg2, arg3, reloced_arg1, reloced_arg2,
                 arg1_size = 0, arg2_size = 0, arg3_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, isXMM, isXMM1, isXMM2;
    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], arg3_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;
    *arg3_st = 0;

    if (!IsRaw && PutSrcLink(rip, 1, line1))
        CatPrint(line1, "\n");
    else
        *line1 = 0;

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

    StrPrint(line2, "%24tp 0x", 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:
                // OC_OP_SIZE_PREFIX (0x66) legacy byte is ignored if it's an SSE instruction, checking early here.
                tmpins = InstEntryFind(rip, opsize, seg_size);
                for (i = 0; i < tmpins->opcode_count; i++)
                {
                    if (tmpins->opcode[i] != rip[i])
                    {
//                      ST_ERR_ST "$HL,0$\nBAD MATCH SSE check #1! %02X with %02X\n", tmpins->opcode[i], rip[i];
//                      Dump(tmpins, sizeof(CInst));"$HL,1$";
                        if (opsize == 32 && seg_size == 64)
                        {
                            tmpins2 = InstEntryFind(rip, 64, seg_size);
                            if (tmpins2 != tmpins)
                                tmpins = tmpins2;
                        }
                        break; // leave for loop
                    }
                }
                if (ARGT_XMM <= tmpins->arg1 <= ARGT_XMM0 ||
                    ARGT_XMM <= tmpins->arg2 <= ARGT_XMM0)
                {
                    for (i = 0; i < tmpins->opcode_count; i++)
                    {
                        if (tmpins->opcode[i] != rip[i])
                        {
//                          ST_ERR_ST "$HL,0$BAD MATCH SSE check #2! %02X with %02X\n", tmpins->opcode[i], rip[i];
//                          Dump(tmpins, sizeof(CInst));"\n$HL,1$";
                            goto sse_check_fail; // evaluate inst op with RIP. if not identical, not a match.
                        }
                    }
                    goto sse_check_jump; // if match, jump to processing. else, treat as legacy prefix.
                }
sse_check_fail:
                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;
    }
sse_check_jump:

    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;
    arg3 = tmpins->arg3;

    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 (arg3_size = tmpins->size3)
    {
        if (Bt(&uasm.signed_arg_mask, arg3))
            CatPrint(arg3_st, "I%d ", arg3_size);
        else
            CatPrint(arg3_st, "U%d ", arg3_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);
        }
    }

    isXMM1 = ARGT_XMM <= arg1 <= ARGT_XMM0;
    isXMM2 = ARGT_XMM <= arg2 <= ARGT_XMM0;
    isXMM = isXMM1 || isXMM2;

    if (isXMM ||
        ARGT_RM8 <= arg1 <= ARGT_RM64 || ARGT_M8 <= arg1 <= ARGT_M64 ||
        ARGT_RM8 <= arg2 <= ARGT_RM64 || ARGT_M8 <= arg2 <= ARGT_M64)
    {
        if (ARGT_XMM32 <= arg2 <= ARGT_XMM0 || // registers are swapped in ModrM when two XMM no indirect
            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 && !isXMM) // SSE instructions have lower bit clear and doesn't mean SIB
            SIB = *rip++;
        if (Mod == 1)
        {
            disp = *rip(U8 *)++;
            CatPrint(reloced_arg1_st, "0x%02X", disp);
        }
        else if (Mod == 2)
        {
            disp = *rip(U32 *)++;
            CatPrint(reloced_arg1_st, "0x%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";
                else if (reloced_arg2_size == 128)
                    ptr = "ST_XMM_REGS";
            }
            if (ptr)
                CatPrint(reloced_arg2_st, "%Z", RM2, ptr);
        }
        if ((RM1 & 7 == 5 || RM1 & 7 == 4 && isXMM) && !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, "[0x%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, "0x%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";
                else if (reloced_arg1_size == 128)
                    ptr = "ST_XMM_REGS";
                if (ptr)
                    CatPrint(reloced_arg1_st, DefineSub(RM1, ptr));
            }
        }
    }

    switch (arg1)
    {
        case ARGT_IMM8:
        case ARGT_UIMM8:
            imm = *rip(U8 *)++;
            CatPrint(arg1_st, "0x%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, "0x%04X", *rip(U16 *)++);
            break;

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

        case ARGT_IMM64:
        case ARGT_UIMM64:
            CatPrint(arg1_st, "0x%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, "[0x%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, "0x%02X", *rip(U8 *)++);
            break;

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

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

        case ARGT_IMM64:
        case ARGT_UIMM64:
            CatPrint(arg2_st, "0x%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, "[0x%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;
    }
    switch (arg3)
    {
        case ARGT_IMM8:
        case ARGT_UIMM8:
            CatPrint(arg3_st, "0x%02X", *rip(U8 *)++);
            break;
    }

    if (tmpins->flags & IEF_ENDING_ZERO)
        rip++;

    if (*arg1_st)
    {
        CatPrint(line1, "%h*c", 12 - StrLen(tmpo->str), ' ');
        CatPrint(line1, " %s", arg1_st);
    }
    if (*arg2_st)
        CatPrint(line1, ", %s", arg2_st);
    if (*arg3_st)
        CatPrint(line1, ", %s", arg3_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");
    if (!IsRaw)
        "$LTCYAN$";
    "        &Function+Offset Machine Code   Instruction  Operands";
    if (!IsRaw)
        "$FG$$HL,1$";
    "\n";
    for (i = 0; i < count; i++)
    {
        Ui(buf, &rip, seg_size);
        "%s", buf;
    }
    if (!IsRaw)
        "$HL,0$";
    "\n";

    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");
    if (!IsRaw)
        "$LTCYAN$";
    "        &Function+Offset Machine Code   Instruction  Operands";
    if (!IsRaw)
        "$FG$$HL,1$";
    "\n";
    while (rip < end_rip)
    {
        Ui(buf, &rip, seg_size);
        "%s", buf;
        i++;
    }
    if (!IsRaw)
        "$HL,0$";
    "\n";

    return i;
}