summaryrefslogtreecommitdiffstats
path: root/src/disasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/disasm.c')
-rw-r--r--src/disasm.c405
1 files changed, 227 insertions, 178 deletions
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);
}