aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--executor/x86_64/asm.c228
-rw-r--r--executor/x86_64/asm.h2
2 files changed, 206 insertions, 24 deletions
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c
index 8e07ee3..73ae568 100644
--- a/executor/x86_64/asm.c
+++ b/executor/x86_64/asm.c
@@ -10,6 +10,127 @@
#define REX_W 0x48
+#ifdef DEBUG
+#include <stdarg.h>
+#include <string.h>
+
+static u8 asm_debug_str_buffer[256];
+static usize asm_debug_str_buffer_index = 0;
+static usize ins_start_offset = 0;
+
+static void asm_debug_str_append(const char *str) {
+ const usize len = strlen(str);
+ am_memcpy(asm_debug_str_buffer + asm_debug_str_buffer_index, str, len);
+ asm_debug_str_buffer_index += len;
+}
+
+static void asm_debug_str_append_num(int num) {
+ char num_str[32];
+ sprintf(num_str, "0x%x", num);
+ asm_debug_str_append(num_str);
+}
+
+static void ins_start(Asm *self) {
+ ins_start_offset = (u8*)self->code_it - (u8*)self->code;
+ asm_debug_str_buffer_index = 0;
+}
+
+static void ins_end(Asm *self, const char *fmt, ...) {
+ usize ins_end_offset;
+ usize i;
+ va_list args;
+
+ va_start(args, fmt);
+ ins_end_offset = (u8*)self->code_it - (u8*)self->code;
+ for(i = ins_start_offset; i < ins_end_offset; ++i) {
+ fprintf(stderr, "%02x ", ((u8*)self->code)[i]);
+ }
+ /* Same padding for all instructions, no matter how long they are */
+ for(i = 0; i < 35 - (ins_end_offset - ins_start_offset)*3; ++i) {
+ putc(' ', stderr);
+ }
+ vfprintf(stderr, fmt, args);
+ putc('\n', stderr);
+ va_end(args);
+}
+
+static const char* reg32_to_str(Reg32 reg) {
+ switch(reg) {
+ case EAX: return "eax";
+ case ECX: return "ecx";
+ case EDX: return "edx";
+ case EBX: return "ebx";
+ case ESP: return "esp";
+ case EBP: return "ebp";
+ case ESI: return "esi";
+ case EDI: return "edi";
+ }
+ assert(bool_false);
+ return NULL;
+}
+
+static const char* reg64_to_str(Reg64 reg) {
+ switch(reg) {
+ case RAX: return "rax";
+ case RCX: return "rcx";
+ case RDX: return "rdx";
+ case RBX: return "rbx";
+ case RSP: return "rsp";
+ case RBP: return "rbp";
+ case RSI: return "rsi";
+ case RDI: return "rdi";
+ }
+ assert(bool_false);
+ return NULL;
+}
+
+static i32 abs(i32 num) {
+ return num >= 0 ? num : -num;
+}
+
+static const char* asm_ptr_to_string(AsmPtr *self) {
+ const char *buf = (const char*)(asm_debug_str_buffer + asm_debug_str_buffer_index);
+ asm_debug_str_append("QWORD PTR [");
+ asm_debug_str_append(reg64_to_str(self->base));
+ if((int)self->index != -1) {
+ asm_debug_str_append(reg64_to_str(self->index));
+ asm_debug_str_append(" * ");
+ asm_debug_str_append_num(1 << self->scale);
+ }
+ if(self->disp < 0)
+ asm_debug_str_append(" - ");
+ else
+ asm_debug_str_append(" + ");
+ asm_debug_str_append_num(abs(self->disp));
+ asm_debug_str_append("]\0");
+ return buf;
+}
+#else
+static void ins_start(Asm *self) {
+ (void)self;
+}
+
+static void ins_end(Asm *self, const char *fmt, ...) {
+ (void)self;
+ (void)fmt;
+}
+
+static const char* reg32_to_str(Reg32 reg) {
+ (void)reg;
+ return NULL;
+}
+
+static const char* reg64_to_str(Reg64 reg) {
+ (void)reg;
+ return NULL;
+}
+
+static const char* asm_ptr_to_string(AsmPtr *self) {
+ (void)self;
+ return NULL;
+}
+#endif
+
void asm_ptr_init(AsmPtr *self, Reg64 base) {
self->base = base;
self->index = -1;
@@ -116,8 +237,10 @@ static isize asm_get_capacity_left(Asm *self) {
#endif
int asm_nop(Asm *self) {
+ ins_start(self);
return_if_error(asm_ensure_capacity(self, 1));
*self->code_it++ = 0x90;
+ ins_end(self, "nop");
return 0;
}
@@ -158,6 +281,7 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) {
*self->code_it++ = rm_byte;
*self->code_it++ = sib_offset;
} else {
+ assert(mem->scale == 0); /* Scale isn't valid without index reg */
if(mem->disp == 0) {
if(mem->base == RBP) {
rm_byte = 0x45;
@@ -188,6 +312,7 @@ static void asm_rr(Asm *self, Reg64 dst, Reg64 src) {
/* TODO: Implement 1 and 2 byte immediate? */
int asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) {
+ ins_start(self);
/* 12 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 12));
*self->code_it++ = REX_W;
@@ -195,99 +320,132 @@ int asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) {
asm_rm(self, dst, 0);
am_memcpy(self->code_it, &immediate, sizeof(immediate));
self->code_it += sizeof(immediate);
+ ins_end(self, "mov %s, 0x%x", asm_ptr_to_string(dst), immediate);
return 0;
}
int asm_mov_mr(Asm *self, AsmPtr *dst, Reg64 src) {
+ ins_start(self);
/* 8 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 8));
*self->code_it++ = REX_W;
*self->code_it++ = 0x89;
asm_rm(self, dst, src);
+ ins_end(self, "mov %s, %s", asm_ptr_to_string(dst), reg64_to_str(src));
return 0;
}
int asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) {
+ ins_start(self);
/* 8 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 8));
*self->code_it++ = REX_W;
*self->code_it++ = 0x8B;
asm_rm(self, src, dst);
+ ins_end(self, "mov %s, %s", reg64_to_str(dst), asm_ptr_to_string(src));
return 0;
}
int asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) {
+ ins_start(self);
/* 10 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 10));
*self->code_it++ = REX_W;
*self->code_it++ = 0xB8 + dst;
am_memcpy(self->code_it, &immediate, sizeof(immediate));
self->code_it += sizeof(immediate);
+ ins_end(self, "mov %s, %ld", reg64_to_str(dst), immediate);
return 0;
}
int asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) {
+ ins_start(self);
/* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = REX_W;
*self->code_it++ = 0x89;
asm_rr(self, dst, src);
+ ins_end(self, "mov %s, %s", reg64_to_str(dst), reg64_to_str(src));
return 0;
}
int asm_add_rr(Asm *self, Reg64 dst, Reg64 src) {
+ ins_start(self);
/* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = REX_W;
*self->code_it++ = 0x01;
asm_rr(self, dst, src);
+ ins_end(self, "add %s, %s", reg64_to_str(dst), reg64_to_str(src));
return 0;
}
int asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) {
+ ins_start(self);
/* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = REX_W;
*self->code_it++ = 0x29;
asm_rr(self, dst, src);
+ ins_end(self, "sub %s, %s", reg64_to_str(dst), reg64_to_str(src));
return 0;
}
int asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) {
+ ins_start(self);
/* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 4));
*self->code_it++ = REX_W;
*self->code_it++ = 0x0F;
*self->code_it++ = 0xAF;
asm_rr(self, dst, src);
+ ins_end(self, "imul %s, %s", reg64_to_str(dst), reg64_to_str(src));
return 0;
}
int asm_pushr(Asm *self, Reg64 reg) {
+ ins_start(self);
return_if_error(asm_ensure_capacity(self, 1));
*self->code_it++ = 0x50 + reg;
+ ins_end(self, "push %s", reg64_to_str(reg));
return 0;
}
int asm_popr(Asm *self, Reg64 reg) {
+ ins_start(self);
return_if_error(asm_ensure_capacity(self, 1));
*self->code_it++ = 0x58 + reg;
+ ins_end(self, "pop %s", reg64_to_str(reg));
return 0;
}
+/* TODO: Remove these !*/
+
/* /r */
#define DEFINE_INS_RM(mnemonic, opcode) \
-int asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \
+int asm_##mnemonic##_rmb(Asm *self, Reg32 dst, Reg32 src) { \
return_if_error(asm_ensure_capacity(self, 2)); \
- *self->code_it++ = opcode; \
- *self->code_it++ = 0xC0 + 8*dst + src; \
+ *self->code_it++ = opcode; \
+ *self->code_it++ = 0xC0 + 8*dst + src; \
return 0; \
} \
\
+int asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \
+ int result; \
+ ins_start(self); \
+ result = asm_##mnemonic##_rmb(self, (Reg32)dst, (Reg32)src); \
+ ins_end(self, #mnemonic" %s, %s", reg32_to_str(dst), reg32_to_str(src)); \
+ return result; \
+} \
+ \
int asm_##mnemonic##_rm64(Asm *self, Reg64 dst, Reg64 src) { \
+ int result; \
+ ins_start(self); \
return_if_error(asm_ensure_capacity(self, 1)); \
- *self->code_it++ = REX_W; \
- return asm_##mnemonic##_rm32(self, (Reg32)dst, (Reg32)src); \
+ *self->code_it++ = REX_W; \
+ result = asm_##mnemonic##_rmb(self, (Reg32)dst, (Reg32)src); \
+ ins_end(self, #mnemonic" %s, %s", reg64_to_str(dst), reg64_to_str(src)); \
+ return result; \
}
DEFINE_INS_RM(mov, 0x8B)
@@ -305,26 +463,38 @@ DEFINE_INS_RM(cmp, 0x3B)
one register the other register can be encoded for that.
*/
#define DEFINE_INS_EXT_IMM(mnemonic, extension) \
-int asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \
- if(abs_i32(immediate) <= INT8_MAX) { \
+int asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i32 immediate) { \
+ if(abs_i32(immediate) <= INT8_MAX) { \
return_if_error(asm_ensure_capacity(self, 3)); \
- *self->code_it++ = 0x83; \
- *self->code_it++ = 0xC0 + 8*extension + reg; \
- *self->code_it++ = (u8)immediate; \
+ *self->code_it++ = 0x83; \
+ *self->code_it++ = 0xC0 + 8*extension + reg; \
+ *self->code_it++ = (u8)immediate; \
} else { \
return_if_error(asm_ensure_capacity(self, 6)); \
- *self->code_it++ = 0x81; \
- *self->code_it++ = 0xC0 + 8*extension + reg; \
+ *self->code_it++ = 0x81; \
+ *self->code_it++ = 0xC0 + 8*extension + reg; \
am_memcpy(self->code_it, &immediate, sizeof(immediate)); \
self->code_it += sizeof(immediate); \
} \
return 0; \
} \
\
+int asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \
+ int result; \
+ ins_start(self); \
+ result = asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \
+ ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \
+ return result; \
+}\
+ \
int asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i32 immediate) { \
+ int result; \
+ ins_start(self); \
return_if_error(asm_ensure_capacity(self, 1)); \
- *self->code_it++ = REX_W; \
- return asm_##mnemonic##_rm32_imm(self, (Reg32)reg, immediate); \
+ *self->code_it++ = REX_W; \
+ result = asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \
+ ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \
+ return result; \
}
DEFINE_INS_EXT_IMM(add, 0)
@@ -343,24 +513,36 @@ DEFINE_INS_EXT_IMM(cmp, 7)
one register the other register can be encoded for that.
*/
#define DEFINE_INS_SHIFT_IMM8(mnemonic, extension) \
-int asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \
+int asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i8 immediate) { \
if(immediate == 1) { \
return_if_error(asm_ensure_capacity(self, 2)); \
- *self->code_it++ = 0xC1; \
- *self->code_it++ = 0xC0 + 8*reg + extension; \
+ *self->code_it++ = 0xC1; \
+ *self->code_it++ = 0xC0 + 8*reg + extension; \
} else { \
return_if_error(asm_ensure_capacity(self, 3)); \
- *self->code_it++ = 0xD1; \
- *self->code_it++ = 0xC0 + 8*reg + extension; \
- *self->code_it++ = immediate; \
+ *self->code_it++ = 0xD1; \
+ *self->code_it++ = 0xC0 + 8*reg + extension; \
+ *self->code_it++ = immediate; \
} \
return 0; \
} \
+ \
+int asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \
+ int result; \
+ ins_start(self); \
+ result = asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \
+ ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \
+ return result; \
+} \
\
int asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i8 immediate) { \
+ int result; \
+ ins_start(self); \
return_if_error(asm_ensure_capacity(self, 1)); \
- *self->code_it++ = REX_W; \
- return asm_##mnemonic##_rm32_imm(self, (Reg32)reg, immediate); \
+ *self->code_it++ = REX_W; \
+ result = asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \
+ ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \
+ return result; \
}
DEFINE_INS_SHIFT_IMM8(rol, 0)
@@ -373,6 +555,7 @@ DEFINE_INS_SHIFT_IMM8(shr, 5)
DEFINE_INS_SHIFT_IMM8(sar, 7)
int asm_ret(Asm *self, u16 bytes) {
+ ins_start(self);
if(bytes == 0) {
return_if_error(asm_ensure_capacity(self, 1));
*self->code_it++ = 0xC3;
@@ -381,5 +564,6 @@ int asm_ret(Asm *self, u16 bytes) {
*self->code_it++ = 0xC2;
am_memcpy(self->code_it, &bytes, sizeof(bytes));
}
+ ins_end(self, "ret 0x%x", bytes);
return 0;
}
diff --git a/executor/x86_64/asm.h b/executor/x86_64/asm.h
index 6fad26a..b374e44 100644
--- a/executor/x86_64/asm.h
+++ b/executor/x86_64/asm.h
@@ -83,8 +83,6 @@ CHECK_RESULT int asm_popr(Asm *self, Reg64 reg);
-
-
CHECK_RESULT int asm_mov_rm32(Asm *self, Reg32 dst, Reg32 src);
CHECK_RESULT int asm_add_rm32(Asm *self, Reg32 dst, Reg32 src);
CHECK_RESULT int asm_sub_rm32(Asm *self, Reg32 dst, Reg32 src);