diff options
-rw-r--r-- | executor/x86_64/asm.c | 228 | ||||
-rw-r--r-- | executor/x86_64/asm.h | 2 |
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); |