summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/disasm.c174
1 files changed, 135 insertions, 39 deletions
diff --git a/src/disasm.c b/src/disasm.c
index c9b839d..e38a6db 100644
--- a/src/disasm.c
+++ b/src/disasm.c
@@ -68,12 +68,14 @@
// ====== !windows.h ======
// ========================
+const u8 x64_max_inst_size = 16U;
const u8 MAX_LEGACY_PREFIXES = 4U;
const u8 legacy_prefixes[] = {
// Operand-size override
0x66,
- 0x67,
// Address-size override
+ 0x67,
+ // Segment override
0x2E,
0x3E,
0x26,
@@ -106,6 +108,26 @@ const u8 REX_prefixes[] = {
0x4F,
};
+const char* registers[] = {
+ "RAX",
+ "RBX",
+ "RCX",
+ "RDX",
+ "RSI",
+ "RDI",
+ "RBP",
+ "RSP",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+ "RIP",
+};
+
const char* ModRM_registers[8U][5U] = {
{ "YMM0", "XMM0", "MMX0", "RAX" },
{ "YMM1", "XMM1", "MMX1", "RCX" },
@@ -154,19 +176,42 @@ struct operand {
Vector_REG, // L
DS_rSI, // X
ES_rSI, // Y
+ Reg,
} src; // Handle eventual SIB byte following ModRM byte
- enum DATA_TYPE {
- TYPE_BYTE = 0x1, // b
- TYPE_WORD = 0x2,
- 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_z = 0x1000, // z
- TYPE_1 = 0x2000, // Hardcoded 1
- } type;
+ union {
+ enum DATA_TYPE {
+ TYPE_NONE = 0x0,
+ TYPE_BYTE = 0x1, // b
+ TYPE_WORD = 0x2,
+ 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_z = 0x1000, // z
+ TYPE_1 = 0x2000, // Hardcoded 1
+ } type;
+ enum REGISTER {
+ RAX,
+ RBX,
+ RCX,
+ RDX,
+ RSI,
+ RDI,
+ RBP,
+ RSP,
+ R8,
+ R9,
+ R10,
+ R11,
+ R12,
+ R13,
+ R14,
+ R15,
+ RIP,
+ } reg;
+ };
// SSE stuff
};
@@ -261,14 +306,14 @@ const struct opcode primary_opcode_map[256U] = {
{ "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO
{ "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO
{ "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO
- { "PUSH", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO
- { "PUSH", { .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 = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO
- { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO
- { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO
- { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO
- { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO
+ { "PUSH", { .src = Reg, .reg = RAX }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RCX }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RDX }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RBX }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RSP }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RBP }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RSI }, { .src = None, .type = TYPE_NONE }},
+ { "PUSH", { .src = Reg, .reg = RDI }, { .src = None, .type = TYPE_NONE }},
{ "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
@@ -611,6 +656,34 @@ u8 is_REX_prefix(u8 byte) {
return FALSE;
}
+u8 has_ModRM_byte(const enum OPERAND_TYPE op_type) {
+ switch (op_type) {
+ case None:
+ return FALSE;
+ case Inst_FAR:
+ return FALSE;
+ case TYPE_E:
+ return TRUE;
+ case ModRM_Reg:
+ return TRUE;
+ case Imm:
+ return FALSE;
+ case ModRM_MEM:
+ return TRUE;
+ case Vector_REG:
+ return FALSE;
+ case DS_rSI:
+ return FALSE;
+ case ES_rSI:
+ return FALSE;
+ case Reg:
+ return FALSE;
+ }
+
+ assert(FALSE);
+ return FALSE;
+}
+
const struct opcode* primary_map_group(u8 opcode, u8 ModRM) {
const u8 reg_size = 0x8;
const u8 reg_byte_mask = 0b111;
@@ -653,10 +726,13 @@ u64 get_immediate(u8** bytes, enum DATA_TYPE type, u8 operand_effective_size) {
} else if (type == TYPE_v) {
if (operand_effective_size == 16U) {
imm = (u16)**bytes;
+ *bytes += 2U;
} else if (operand_effective_size == 32U) {
imm = (u32)**bytes;
+ *bytes += 4U;
} else if (operand_effective_size == 64U) {
imm = (u64)**bytes;
+ *bytes += 8U;
} else {
print("ERROR: Unhandled operand type\n");
}
@@ -668,7 +744,7 @@ u64 get_immediate(u8** bytes, enum DATA_TYPE type, u8 operand_effective_size) {
*bytes += 2U;
} else {
imm = (u32)**bytes;
- *bytes += 2U;
+ *bytes += 4U;
}
} else {
print("ERROR: Unhandled operand type\n");
@@ -720,15 +796,13 @@ void unassemble(u8* start, u64 size) {
u8 legacy_prefixes_count = 0U;
u8 effective_operand_size = 32U; // 32 by default in 64bit mode
i32 effective_address = -1;
- (void)effective_address; // Not used yet
- u8 operand_size_override_66 = FALSE;
+ (void)effective_address; // Not used yet
u8 operand_size_override_REX = FALSE;
(void)operand_size_override_REX; // Not used yet
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;
- operand_size_override_66 = TRUE;
}
legacy_prefixes_count++;
current_byte++;
@@ -737,7 +811,7 @@ void unassemble(u8* start, u64 size) {
if (is_REX_prefix(*current_byte)) {
REX = *current_byte;
- if (REXW(REX) && operand_size_override_66 == FALSE) {
+ if (REXW(REX)) {
effective_operand_size = 64U;
operand_size_override_REX = TRUE;
}
@@ -745,23 +819,43 @@ void unassemble(u8* start, u64 size) {
current_byte++;
}
- // TODO: VEX, XOP prefixes
+ // TODO: VEX, XOP prefixes and there escape sequences
- u8 op_byte = *current_byte;
- current_byte++;
- u8 ModRM = *current_byte;
+ u8 has_ModRM = FALSE;
+ u8 ModRM = 0U;
const struct opcode* op = NULL;
- if (op_byte == 0x0F) { // Secondary op code map needed
+ if (current_byte[0U] == 0x0F && current_byte[1U] == 0x0F) { // 3DNow!
+ assert(FALSE);
+ current_byte += 2U;
+ } else if (current_byte[0U] == 0x0F && (current_byte[1U] == 0x38 || current_byte[1U] == 0x3A)) { // SSE
+ assert(FALSE);
+ current_byte += 2U;
+ } else if (current_byte[0U] == 0x0F) { // Secondary op code map needed
+ assert(FALSE);
current_byte++;
- } else if ((op = primary_map_group(op_byte, ModRM)) != NULL) {
- } else {
- op = &primary_opcode_map[op_byte];
+ } else { // Primary op code map
+ if ((op = primary_map_group(current_byte[0U], current_byte[1U])) != NULL) {
+ has_ModRM = TRUE;
+ ModRM = current_byte[1U];
+ current_byte += 2U;
+ } else {
+ op = &primary_opcode_map[current_byte[0U]];
+ current_byte++;
+
+ has_ModRM = has_ModRM_byte(op->dst_operand.src) || has_ModRM_byte(op->src_operand.src);
+ if (has_ModRM) {
+ ModRM = *current_byte;
+ current_byte++;
+ }
+ }
}
+
u8 disp_bytes_count = 0U;
u8 has_src_SIB = FALSE;
u8 has_dst_SIB = FALSE;
- if (op->src_operand.src & (TYPE_E | ModRM_Reg) || op->dst_operand.src & (TYPE_E | ModRM_Reg)) {
+ // NOTE: could we test has_ModRM instead ?
+ if (op->src_operand.src == TYPE_E || op->src_operand.src == ModRM_Reg || op->dst_operand.src == TYPE_E || op->dst_operand.src == ModRM_Reg) {
u8 Mod = MODRM_MOD(ModRM);
u8 RM = MODRM_RM(ModRM);
@@ -769,7 +863,7 @@ void unassemble(u8* start, u64 size) {
// Displacement detection
if (Mod == 0b00 && RM == 0b101) {
disp_bytes_count = mod_to_disp_size[Mod];
- } else if (Mod != 0b11) {
+ } else if (Mod == 0b01 || Mod == 0b10) {
disp_bytes_count = mod_to_disp_size[Mod];
}
@@ -784,15 +878,13 @@ void unassemble(u8* start, u64 size) {
// NOTE: We probably can't have both operand needing an SIB byte
assert(!(has_src_SIB == has_dst_SIB == TRUE));
}
-
- current_byte++;
}
// SIB
u8 SIB = *current_byte;
if (has_src_SIB || has_dst_SIB) {
u8 Mod = MODRM_MOD(ModRM);
- if (SIB_BASE(SIB)) {
+ if (SIB_BASE(SIB) == 0b101) {
disp_bytes_count = mod_to_disp_size[Mod];
}
current_byte++;
@@ -823,7 +915,7 @@ void unassemble(u8* start, u64 size) {
u8 inst_size = (u8)(current_byte - inst_start);
- for (u8 index = 0U; index < 6U; index++) {
+ for (u8 index = 0U; index < x64_max_inst_size; index++) {
if (index < inst_size) {
print("%.2x ", inst_start[index]);
} else {
@@ -845,6 +937,8 @@ void unassemble(u8* start, u64 size) {
if (Mod == 0b11) {
print(" %s", ModRM_registers[RM][3U]);
}
+ } else if (op->src_operand.src == Reg) {
+ print(" %s", registers[op->src_operand.reg]);
}
if (has_src_SIB) {
@@ -861,6 +955,8 @@ void unassemble(u8* start, u64 size) {
{
if (op->dst_operand.src == Imm) {
print(" %x", dst_imm);
+ } else if (op->dst_operand.src == Reg) {
+ print(", %s", registers[op->dst_operand.reg]);
}
if (has_dst_SIB) {