From 87075f30cb51199690e367184cfacf2d83400435 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Sat, 25 Jul 2026 16:33:09 +0200 Subject: Add support for register operands encoded in the op code --- src/disasm.c | 405 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 227 insertions(+), 178 deletions(-) (limited to 'src') diff --git a/src/disasm.c b/src/disasm.c index c312348..36df605 100644 --- a/src/disasm.c +++ b/src/disasm.c @@ -89,6 +89,7 @@ const u8 legacy_prefixes[] = { 0xF3, }; +const u8 REX_prefix_mask = 0b01000000; const u8 REX_prefixes[] = { 0x40, 0x41, @@ -187,7 +188,26 @@ const char* registers[] = { "SS", // Ignored in 64 mode }; -const char* ModRM_registers[8U][5U] = { +const char* indexed_registers[16U][8U] = { // [reg_index][size] + { "AL", "AX", "EAX", "RAX" }, + { "BL", "BX", "EBX", "RBX" }, + { "CL", "CX", "ECX", "RCX" }, + { "DL", "DX", "EDX", "RDX" }, + { "SIL", "SI", "ESI", "RSI" }, + { "DIL", "DI", "EDI", "RDI" }, + { "BPL", "BP", "EBP", "RBP" }, + { "SPL", "SP", "ESP", "RSP" }, + { "R8B", "R8W", "R8D", "R8" }, + { "R9B", "R9W", "R9D", "R9" }, + { "R10B", "R10W", "R10D", "R10" }, + { "R11B", "R11W", "R11D", "R11" }, + { "R12B", "R12W", "R12D", "R12" }, + { "R13B", "R13W", "R13D", "R13" }, + { "R14B", "R14W", "R14D", "R14" }, + { "R15B", "R15W", "R15D", "R15" }, +}; + +const char* ModRM_registers[16U][5U] = { { NULL, "RAX", "MMX0", "XMM0", "YMM0" }, { NULL, "RCX", "MMX1", "XMM1", "YMM1" }, { NULL, "RDX", "MMX2", "XMM2", "YMM2" }, @@ -195,7 +215,15 @@ const char* ModRM_registers[8U][5U] = { { "AH", "RSP", "MMX4", "XMM4", "YMM4" }, { "CH", "RBP", "MMX5", "XMM5", "YMM5" }, { "DH", "RSI", "MMX6", "XMM6", "YMM6" }, - { "BH", "RDI", "MMX7", "XMM7", "YMM7" } + { "BH", "RDI", "MMX7", "XMM7", "YMM7" }, + { NULL, "R8", NULL, NULL, NULL }, + { NULL, "R9", NULL, NULL, NULL }, + { NULL, "R10", NULL, NULL, NULL }, + { NULL, "R11", NULL, NULL, NULL }, + { NULL, "R12", NULL, NULL, NULL }, + { NULL, "R13", NULL, NULL, NULL }, + { NULL, "R14", NULL, NULL, NULL }, + { NULL, "R15", NULL, NULL, NULL }, }; const char* SIB_index_registers[8U] = { @@ -233,24 +261,27 @@ struct operand { Imm, // I TYPE_J, // Relative offset added to RIP ModRM_MEM, // M, mod != 0b11 + Operand_Off, // O Vector_REG, // L ModRM_Seg_Reg, // S TYPE_R, // R mod != 0b11 - DS_rSI, // X - ES_rSI, // Y + DS_RSI, // X + ES_RDI, // Y Reg, + Reg_Mask, } src; // Handle eventual SIB byte following ModRM byte union { enum DATA_TYPE { TYPE_NONE = 0x0, - TYPE_BYTE = 0x1, // b - TYPE_WORD = 0x2, // w - TYPE_DWORD = 0x4, - TYPE_QWORD = 0x8, - TYPE_FP = 0x10, - TYPE_v = 0x1f, // v - TYPE_p = 0x20, // 32 or 48 bit depending on 16 or 32 bit operand size + TYPE_a = 0x1, // 16 or 32 bit operand depending on the operand size + TYPE_BYTE = 0x2, // b + TYPE_WORD = 0x4, // w + TYPE_DWORD = 0x8, + TYPE_QWORD = 0x10, + TYPE_FP = 0x20, + TYPE_v = 0x2f, // v + TYPE_p = 0x40, // 32 or 48 bit depending on 16 or 32 bit operand size TYPE_z = 0x1000, // z TYPE_1 = 0x2000, // Hardcoded 1 } type; @@ -324,6 +355,7 @@ struct operand { R15D, R15, RIP, + RFLAGS, // Segments CS, DS, // Ignored in 64 mode @@ -340,6 +372,7 @@ struct opcode { const char* name; struct operand src_operand; struct operand dst_operand; + const char* alt_name; }; const struct opcode rep_f3_opcode_map[] = { @@ -385,7 +418,7 @@ const struct opcode primary_opcode_map[256U] = { { "AND", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, { "AND", { .src = Reg, .reg = AL }, { .src = Imm, .type = TYPE_BYTE }}, { "AND", { .src = Reg, .reg = RAX }, { .src = Imm, .type = TYPE_z }}, - { "seg", { .src = Reg, .reg = ES }, { .src = None }}, + { "INVALID", { .src = None }, { .src = None }}, // ES segment override prefix { "DAA", { .src = None }, { .src = None }}, { "SUB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, { "SUB", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, @@ -393,7 +426,7 @@ const struct opcode primary_opcode_map[256U] = { { "SUB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, { "SUB", { .src = Reg, .reg = AL }, { .src = Imm, .type = TYPE_BYTE }}, { "SUB", { .src = Reg, .reg = RAX }, { .src = Imm, .type = TYPE_z }}, - { "seg", { .src = Reg, .reg = CS }, { .src = None }}, + { "INVALID", { .src = None }, { .src = None }}, // CS segment override prefix { "DAS", { .src = None }, { .src = None }}, { "XOR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, { "XOR", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, @@ -401,7 +434,7 @@ const struct opcode primary_opcode_map[256U] = { { "XOR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, { "XOR", { .src = Reg, .reg = AL }, { .src = Imm, .type = TYPE_BYTE }}, { "XOR", { .src = Reg, .reg = RAX }, { .src = Imm, .type = TYPE_z }}, - { "seg", { .src = Reg, .reg = SS }, { .src = None }}, + { "INVALID", { .src = None }, { .src = None }}, // SS segment override prefix { "AAA", { .src = None }, { .src = None }}, { "CMP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, { "CMP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, @@ -409,56 +442,56 @@ const struct opcode primary_opcode_map[256U] = { { "CMP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, { "CMP", { .src = Reg, .reg = AL }, { .src = Imm, .type = TYPE_BYTE }}, { "CMP", { .src = Reg, .reg = RAX }, { .src = Imm, .type = TYPE_z }}, - { "seg", { .src = Reg, .reg = DS }, { .src = None }}, + { "INVALID", { .src = None }, { .src = None }}, // DS segment override prefix { "AAS", { .src = None }, { .src = None }}, - { "INC", { .src = Reg, .reg = EAX }, { .src = None }}, - { "INC", { .src = Reg, .reg = ECX}, { .src = None }}, - { "INC", { .src = Reg, .reg = EDX }, { .src = None }}, - { "INC", { .src = Reg, .reg = EBX }, { .src = None }}, - { "INC", { .src = Reg, .reg = ESP }, { .src = None }}, - { "INC", { .src = Reg, .reg = EBP }, { .src = None }}, - { "INC", { .src = Reg, .reg = ESI }, { .src = None }}, - { "INC", { .src = Reg, .reg = EDI }, { .src = None }}, - { "DEC", { .src = Reg, .reg = EAX }, { .src = None }}, - { "DEC", { .src = Reg, .reg = ECX }, { .src = None }}, - { "DEC", { .src = Reg, .reg = EDX }, { .src = None }}, - { "DEC", { .src = Reg, .reg = EBX }, { .src = None }}, - { "DEC", { .src = Reg, .reg = ESP }, { .src = None }}, - { "DEC", { .src = Reg, .reg = EBP }, { .src = None }}, - { "DEC", { .src = Reg, .reg = ESI }, { .src = None }}, - { "DEC", { .src = Reg, .reg = EDI }, { .src = None }}, - { "PUSH", { .src = Reg, .reg = RAX }, { .src = None, .type = TYPE_NONE }}, // TODO: RAX/r8 - { "PUSH", { .src = Reg, .reg = RCX }, { .src = None, .type = TYPE_NONE }}, // TODO: RCX/r9 - { "PUSH", { .src = Reg, .reg = RDX }, { .src = None, .type = TYPE_NONE }}, // TODO: RDX/r10k - { "PUSH", { .src = Reg, .reg = RBX }, { .src = None, .type = TYPE_NONE }}, // TODO: RBX/r11 - { "PUSH", { .src = Reg, .reg = RSP }, { .src = None, .type = TYPE_NONE }}, // TODO: RSP/r12 - { "PUSH", { .src = Reg, .reg = RBP }, { .src = None, .type = TYPE_NONE }}, // TODO: RBP/r13 - { "PUSH", { .src = Reg, .reg = RSI }, { .src = None, .type = TYPE_NONE }}, // TODO: RSI/r14 - { "PUSH", { .src = Reg, .reg = RDI }, { .src = None, .type = TYPE_NONE }}, // TODO: RDI/r15 - { "POP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO - { "POP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO - { "POP", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO - { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INC", { .src = Reg, .reg = EAX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = ECX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = EDX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = EBX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = ESP }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = EBP }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = ESI }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "INC", { .src = Reg, .reg = EDI }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = EAX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = ECX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = EDX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = EBX }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = ESP }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = EBP }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = ESI }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "DEC", { .src = Reg, .reg = EDI }, { .src = None }}, // Invalid in 64 bit mode, REX prefix + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "PUSH", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, + { "POP", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = None }}, { "PUSHA/D", { .src = None }, { .src = None}}, { "POPA/D", { .src = None }, { .src = None }}, - { "BOUND", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO - { "ARPL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "INVALID", { .src = None }, { .src = None }}, // Operand size overide prefix + { "BOUND", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = ModRM_MEM, .type = TYPE_a }}, + { "MOVSXD", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // ARPL is invalid in 64 mode + { "INVALID", { .src = None }, { .src = None }}, // FS segment override prefix + { "INVALID", { .src = None }, { .src = None }}, // SG segment override prefix + { "INVALID", { .src = None }, { .src = None }}, // Operand size override prefix { "INVALID", { .src = None }, { .src = None }}, // Address size override prefix - { "PUSH", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "PUSH", { .src = Imm, .type = TYPE_z }, { .src = None }}, { "IMUL", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO - { "PUSH", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "PUSH", { .src = Imm, .type = TYPE_BYTE }, { .src = None }}, { "IMUL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "INSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "INSW/D", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "OUTS/B", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "OUTS/W/D", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INSB", { .src = ES_RDI, .type = TYPE_BYTE }, { .src = Reg, .reg = DX }}, + { "INSW/D", { .src = ES_RDI, .type = TYPE_z }, { .src = Reg, .reg = DX }}, // TODO + { "OUTS/B", { .src = Reg, .reg = DX }, { .src = DS_RSI, .type = TYPE_BYTE }}, // TODO + { "OUTS/W/D", { .src = Reg, .reg = DX }, { .src = DS_RSI, .type = TYPE_z }}, // TODO { "JO", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, { "JNO", { .src = TYPE_J, .type = TYPE_BYTE}, { .src = None }}, { "JB", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, @@ -467,14 +500,14 @@ const struct opcode primary_opcode_map[256U] = { { "JNZ", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, { "JBE", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, { "JNBE", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, - { "JS", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO - { "JNS", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO - { "JP", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO - { "JNP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "JL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "JNL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "JLE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "JNLE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JS", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, + { "JNS", { .src = TYPE_J, .type = TYPE_BYTE}, { .src = None }}, + { "JP", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, + { "JNP", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, + { "JL", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, + { "JNL", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, + { "JLE", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, + { "JNLE", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, { "INVALID", { .src = None }, { .src = None }}, // Group 1 Opcode { "INVALID", { .src = None }, { .src = None }}, // Group 1 Opcode { "INVALID", { .src = None }, { .src = None }}, // Group 1 Opcode @@ -487,64 +520,64 @@ const struct opcode primary_opcode_map[256U] = { { "MOV", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, { "MOV", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "MOV", { .src = ModRM_Seg_Reg, .type = TYPE_WORD }, { .src = TYPE_E, .type = TYPE_WORD }}, { "LEA", { .src = ModRM_Reg, .type = TYPE_v }, { .src = ModRM_MEM }}, { "MOV", { .src = ModRM_Seg_Reg, .type = TYPE_WORD }, { .src = TYPE_E, .type = TYPE_WORD }}, { "INVALID", { .src = None }, { .src = None }}, // Group 1 Opcode - { "NOP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "CBW/WDE/DQE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "CWD/DQ/QO", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "CALL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }, .alt_name = "NOP" }, // NOP or XCHG depending on REX.B + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "XCHG", { .src = Reg_Mask, .type = TYPE_QWORD }, { .src = Reg, .reg = RAX }}, + { "CBW/WDE/DQE", { .src = None }, { .src = None }}, // TODO + { "CWD/DQ/QO", { .src = None }, { .src = None }}, // TODO + { "CALL", { .src = Inst_FAR, .type = TYPE_p }, { .src = None }}, { "F/WAIT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "PUSHF/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "POPF/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "SAHF", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "LAHF", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOVSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOBSW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "CMPSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "CMPSW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "TEST", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "TEST", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "STOSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "STOW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "LODSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "LODSW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "SCASB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "SCASW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSHF/D/Q", { .src = Reg, .reg = RFLAGS }, { .src = None }}, // TODO + { "POPF/D/Q", { .src = Reg, .reg = RFLAGS }, { .src = None }}, // TODO + { "SAHF", { .src = None }, { .src = None }}, + { "LAHF", { .src = None }, { .src = None }}, + { "MOV", { .src = Reg, .reg = AL }, { .src = Operand_Off, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg, .reg = RAX }, { .src = Operand_Off, .type = TYPE_v }}, + { "MOV", { .src = Operand_Off, .type = TYPE_BYTE }, { .src = Reg, .reg = AL }}, + { "MOV", { .src = Operand_Off, .type = TYPE_v }, { .src = Reg, .reg = RAX }}, + { "MOVSB", { .src = ES_RDI, .type = TYPE_BYTE }, { .src = DS_RSI, .type = TYPE_BYTE }}, + { "MOBSW/D/Q", { .src = ES_RDI, .type = TYPE_v }, { .src = DS_RSI, .type = TYPE_v }}, // TODO + { "CMPSB", { .src = DS_RSI, .type = TYPE_BYTE }, { .src = ES_RDI, .type = TYPE_BYTE }}, + { "CMPSW/D/Q", { .src = DS_RSI, .type = TYPE_v }, { .src = ES_RDI, .type = TYPE_v }}, // TODO + { "TEST", { .src = Reg, .reg = AL }, { .src = Imm, .type = TYPE_BYTE }}, + { "TEST", { .src = Reg, .reg = RAX }, { .src = Imm, .type = TYPE_z }}, + { "STOSB", { .src = ES_RDI, .type = TYPE_BYTE }, { .src = Reg, .reg = AL }}, + { "STOW/D/Q", { .src = ES_RDI, .type = TYPE_v }, { .src = Reg, .reg = RAX }}, // TODO + { "LODSB", { .src = Reg, .reg = AL }, { .src = DS_RSI, .type = TYPE_BYTE }}, + { "LODSW/D/Q", { .src = Reg, .reg = RAX }, { .src = DS_RSI, .type = TYPE_v }}, // TODO + { "SCASB", { .src = Reg, .reg = AL }, { .src = ES_RDI, .type = TYPE_BYTE }}, + { "SCASW/D/Q", { .src = Reg, .reg = RAX }, { .src = ES_RDI, .type = TYPE_v }}, // TODO + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, + { "MOV", { .src = Reg_Mask, .type = TYPE_v }, { .src = Imm, .type = TYPE_v }}, { "INVALID", { .src = None }, { .src = None }}, // Group 2 opcode { "INVALID", { .src = None }, { .src = None }}, // Group 2 opcode - { "RET", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO - { "RET", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "LES", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO - { "LDS", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "RET near", { .src = Imm, .type = TYPE_WORD }, { .src = None }}, + { "RET near", { .src = None }, { .src = None }}, + { "LES", { .src = ModRM_Reg, .type = TYPE_z }, { .src = ModRM_MEM, .type = TYPE_p }}, // Invalid in 64bit mode, VEX prefix + { "LDS", { .src = ModRM_Reg, .type = TYPE_z }, { .src = ModRM_MEM, .type = TYPE_p }}, // Invalid in 64bit mode, VEX prefix { "INVALID", { .src = None }, { .src = None }}, // Group 11 opcode { "INVALID", { .src = None }, { .src = None }}, // Group 11 opcode { "ENTER", { .src = ModRM_Reg, .type = TYPE_WORD }, { .src = Imm, .type = TYPE_BYTE }}, @@ -554,7 +587,7 @@ const struct opcode primary_opcode_map[256U] = { { "INT 3", { .src = None }, { .src = None }}, { "INT", { .src = Imm, .type = TYPE_BYTE }, { .src = None }}, { "INTO", { .src = None }, { .src = None }}, // Invalid in 64bit mode - { "IRET/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "IRET/D/Q", { .src = None }, { .src = None }}, { "INVALID", { .src = None }, { .src = None }}, // Group 2 Opcode { "INVALID", { .src = None }, { .src = None }}, // Group 2 Opcode { "INVALID", { .src = None }, { .src = None }}, // Group 2 Opcode @@ -562,7 +595,7 @@ const struct opcode primary_opcode_map[256U] = { { "AAM", { .src = Imm, .type = TYPE_BYTE }, { .src = None }}, { "AAD", { .src = Imm, .type = TYPE_BYTE}, { .src = None }}, { "INVALID", { .src = None }, { .src = None }}, // invalid - { "XLAT", { .src = None }, { .src = None }}, // TODO + { "XLAT/B", { .src = None }, { .src = None }}, // TODO { "INVALID", { .src = None }, { .src = None }}, // TODO x87 instructions { "INVALID", { .src = None }, { .src = None }}, // TODO x87 instructions { "INVALID", { .src = None }, { .src = None }}, // TODO x87 instructions @@ -571,10 +604,10 @@ const struct opcode primary_opcode_map[256U] = { { "INVALID", { .src = None }, { .src = None }}, // TODO x87 instructions { "INVALID", { .src = None }, { .src = None }}, // TODO x87 instructions { "INVALID", { .src = None }, { .src = None }}, // TODO x87 instructions - { "LOOPNE/NZ", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO - { "LOOPE/Z", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LOOPNE/NZ", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, // TODO + { "LOOPE/Z", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, // TODO { "LOOP", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, - { "JrCXZ", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JrCXZ", { .src = TYPE_J, .type = TYPE_BYTE }, { .src = None }}, { "IN", { .src = Reg, .reg = AL }, { .src = Imm, .type = TYPE_BYTE }}, { "IN", { .src = Reg, .reg = EAX }, { .src = Imm, .type = TYPE_BYTE }}, { "OUT", { .src = Imm, .type = TYPE_BYTE }, { .src = Reg, .reg = AL }}, @@ -587,10 +620,10 @@ const struct opcode primary_opcode_map[256U] = { { "IN", { .src = Reg, .reg = EAX }, { .src = Reg, .reg = DX }}, { "OUT", { .src = Reg, .reg = DX }, { .src = Reg, .reg = AL }}, { "OUT", { .src = Reg, .reg = DX }, { .src = Reg, .reg = EAX }}, - { "LOCK", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INVALID", { .src = None }, { .src = None }}, // LOCK prefix { "INT1", { .src = None }, { .src = None }}, - { "REPNE", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO - { "REP/E", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "INVALID", { .src = None }, { .src = None }}, // REPNE prefix + { "INVALID", { .src = None }, { .src = None }}, // REP/REPE prefix { "HLT", { .src = None }, { .src = None }}, { "CMC", { .src = None }, { .src = None }}, { "INVALID", { .src = None }, { .src = None }}, // Group 3 opcode @@ -694,23 +727,23 @@ const struct opcode group_2[48U] = { { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, { "SAR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, // Opcode 0xD2 - { "ROL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "ROR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "RCL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "RCR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SHR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SAR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "ROL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "ROR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "RCL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "RCR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "SHR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, + { "SAR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Reg, .reg = CL }}, // Opcode 0xD3 - { "ROL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "ROR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "RCL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "RCR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SHR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL - { "SAR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "ROL", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "ROR", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "RCL", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "RCR", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "SHR", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, + { "SAR", { .src = TYPE_E, .type = TYPE_v }, { .src = Reg, .reg = CL }}, }; const struct opcode group_3[16U] = { @@ -769,14 +802,25 @@ u8 is_legacy_prefix(u8 byte) { } u8 is_REX_prefix(u8 byte) { - for (u8 index = 0U; index < sizeof(REX_prefixes); index++) { - if (byte == REX_prefixes[index]) { - return TRUE; - } - } - return FALSE; + return (byte & REX_prefix_mask) == REX_prefix_mask; } +#define MODRM_MOD(ModRM) (ModRM >> 6U) +#define MODRM_REG(ModRM) ((ModRM & 0b00111000) >> 0x3) +#define MODRM_RM(ModRM) (ModRM & 0b00000111) + +#define SIB_SCALE(SIB) (SIB >> 6U) +#define SIB_INDEX(SIB) ((SIB & 0b00111000) >> 0x3) +#define SIB_BASE(SIB) (SIB & 0b00000111) + +#define REXW(REX) ((REX & 0b00001000) >> 3U) +#define REXR(REX) ((REX & 0b00000100) << 1U) +#define REXX(REX) ((REX & 0b00000010) << 2U) +#define REXB(REX) ((REX & 0b00000001) << 3U) + +const u8 REG_MASK = 0b00000111; +#define GET_REG_INDEX(op) op & REG_MASK + // TODO: Rework this messy function and params const char* get_ModRM_reg(u8 val, u8 operand_size, u8 use_3DNow, u8 use_SSE) { assert(val < 8U); @@ -817,18 +861,22 @@ u8 has_ModRM_byte(const enum OPERAND_TYPE op_type) { return FALSE; case ModRM_MEM: return TRUE; + case Operand_Off: + return FALSE; case Vector_REG: return FALSE; case ModRM_Seg_Reg: return TRUE; case TYPE_R: return TRUE; - case DS_rSI: + case DS_RSI: return FALSE; - case ES_rSI: + case ES_RDI: return FALSE; case Reg: return FALSE; + case Reg_Mask: + return FALSE; } assert(FALSE); @@ -837,8 +885,7 @@ u8 has_ModRM_byte(const enum OPERAND_TYPE op_type) { const struct opcode* primary_map_group(u8 opcode, u8 ModRM) { const u8 reg_size = 0x8; - const u8 reg_byte_mask = 0b111; - u8 reg = (ModRM >> 3U) & reg_byte_mask; + u8 reg = MODRM_REG(ModRM); if (0x80 <= opcode && opcode <= 0x83) { return &group_1[(opcode - 0x80) * reg_size + reg]; } else if (opcode == 0x8F) { @@ -963,19 +1010,6 @@ u8 get_immediate_size(enum DATA_TYPE type, u8 operand_effective_size) { } } -#define MODRM_MOD(ModRM) (ModRM >> 6U) -#define MODRM_REG(ModRM) ((ModRM & 0b00111000) >> 0x3) -#define MODRM_RM(ModRM) (ModRM & 0b00000111) - -#define SIB_SCALE(SIB) (SIB >> 6U) -#define SIB_INDEX(SIB) ((SIB & 0b00111000) >> 0x3) -#define SIB_BASE(SIB) (SIB & 0b00000111) - -#define REXW(REX) ((REX & 0b00001000) >> 3U) -#define REXR(REX) ((REX & 0b00000100) >> 2U) -#define REXX(REX) ((REX & 0b00000010) >> 1U) -#define REXB(REX) (REX & 0b00000001) - // void unassemble(CONTEXT* ctx, u32 count) { void unassemble(u8* start, u64 size) { // u8* current_byte = (u8*)ctx->Rip; @@ -991,7 +1025,6 @@ void unassemble(u8* start, u64 size) { u8 effective_operand_size = 32U; // 32 by default in 64bit mode u8 effective_address_size = 64U; // 64 by default in 64bit mode UNUSED_VAR(effective_address_size); - u8 REX = 0U; while (is_legacy_prefix(*current_byte) && legacy_prefixes_count < MAX_LEGACY_PREFIXES) { if (*current_byte == 0x66) { // Override effective operand size effective_operand_size = 16U; @@ -1002,14 +1035,21 @@ void unassemble(u8* start, u64 size) { current_byte++; } - if (is_REX_prefix(*current_byte)) { - REX = *current_byte; - - if (REXW(REX)) { - effective_operand_size = 64U; - } - + u8 has_REX_prefix = FALSE; + u8 ModRM_reg_extended = 0U; + u8 ModRM_RM_extended = 0U; + UNUSED_VAR(ModRM_RM_extended); + u8 SIB_index_extended = 0U; + UNUSED_VAR(SIB_index_extended); + if ((has_REX_prefix = ((*current_byte & REX_prefix_mask) == REX_prefix_mask)) == TRUE) { + u8 REX = *current_byte; current_byte++; + + // See table 1-15 + ModRM_reg_extended = REXR(REX); + SIB_index_extended = REXX(REX); + ModRM_RM_extended = REXB(REX); + effective_operand_size = REXW(REX) ? 64U : effective_operand_size; } // TODO: VEX, XOP prefixes and there escape sequences @@ -1018,6 +1058,7 @@ void unassemble(u8* start, u64 size) { u8 ModRM = 0U; u8 use_3DNow_reg = FALSE; u8 use_SSE_reg = FALSE; + u8 op_byte = 0U; const struct opcode* op = NULL; if (current_byte[0U] == 0x0F && current_byte[1U] == 0x0F) { // 3DNow! assert(FALSE); @@ -1033,10 +1074,12 @@ void unassemble(u8* start, u64 size) { } else { // Primary op code map if ((op = primary_map_group(current_byte[0U], current_byte[1U])) != NULL) { has_ModRM = TRUE; + op_byte = current_byte[0U]; ModRM = current_byte[1U]; current_byte += 2U; } else { - op = &primary_opcode_map[current_byte[0U]]; + op_byte = current_byte[0U]; + op = &primary_opcode_map[op_byte]; current_byte++; has_ModRM = has_ModRM_byte(op->dst_operand.src) || has_ModRM_byte(op->src_operand.src); @@ -1129,7 +1172,7 @@ void unassemble(u8* start, u64 size) { } print("%s", op->name); - // Src operand + // print src operand { switch(op->src_operand.src) { case None: @@ -1148,7 +1191,7 @@ void unassemble(u8* start, u64 size) { break; } case ModRM_Reg: - print(" %s", get_ModRM_reg(MODRM_REG(ModRM), effective_operand_size, use_3DNow_reg, use_SSE_reg)); + print(" %s", get_ModRM_reg(MODRM_REG(ModRM) + ModRM_reg_extended, effective_operand_size, use_3DNow_reg, use_SSE_reg)); break; case Imm: print(" 0x%x", src_imm); @@ -1159,6 +1202,9 @@ void unassemble(u8* start, u64 size) { case Reg: print(" %s", registers[op->src_operand.reg]); break; + case Reg_Mask: + print(" %s", indexed_registers[op_byte & Reg_Mask]); + break; default: assert(FALSE); } @@ -1192,7 +1238,7 @@ void unassemble(u8* start, u64 size) { print(","); } - // Dst operand + // print dst operand { switch(op->dst_operand.src) { case None: @@ -1211,7 +1257,7 @@ void unassemble(u8* start, u64 size) { break; } case ModRM_Reg: - print(" %s", get_ModRM_reg(MODRM_REG(ModRM), effective_operand_size, use_3DNow_reg, use_SSE_reg)); + print(" %s", get_ModRM_reg(MODRM_REG(ModRM) + ModRM_reg_extended, effective_operand_size, use_3DNow_reg, use_SSE_reg)); break; case Imm: print(" 0x%x", dst_imm); @@ -1222,6 +1268,9 @@ void unassemble(u8* start, u64 size) { case Reg: print(" %s", registers[op->src_operand.reg]); break; + case Reg_Mask: + print(" %s", indexed_registers[op_byte & Reg_Mask]); + break; default: assert(FALSE); } -- cgit v1.3