diff options
Diffstat (limited to 'executor/x86_64/asm.c')
-rw-r--r-- | executor/x86_64/asm.c | 86 |
1 files changed, 66 insertions, 20 deletions
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c index 73ae568..f032538 100644 --- a/executor/x86_64/asm.c +++ b/executor/x86_64/asm.c @@ -35,6 +35,10 @@ static void ins_start(Asm *self) { asm_debug_str_buffer_index = 0; } +static int max(int a, int b) { + return a >= b ? a : b; +} + static void ins_end(Asm *self, const char *fmt, ...) { usize ins_end_offset; usize i; @@ -46,7 +50,7 @@ static void ins_end(Asm *self, const char *fmt, ...) { 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) { + for(i = 0; i < (usize)max(0, 35 - (ins_end_offset - ins_start_offset)*3); ++i) { putc(' ', stderr); } vfprintf(stderr, fmt, args); @@ -160,9 +164,9 @@ void asm_ptr_init_index_disp(AsmPtr *self, Reg64 base, Reg64 index, i32 disp) { } int asm_init(Asm *self) { - self->size = am_pagesize(); - amal_log_debug("asm: page size: %u", self->size); - self->code = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + self->allocated_size = am_pagesize(); + amal_log_debug("asm: page size: %u", self->allocated_size); + self->code = mmap(NULL, self->allocated_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(self->code == MAP_FAILED) return -errno; self->code_it = self->code; @@ -171,12 +175,17 @@ int asm_init(Asm *self) { void asm_deinit(Asm *self) { if(self->code) - munmap(self->code, self->size); + munmap(self->code, self->allocated_size); self->code = NULL; self->code_it = NULL; - self->size = 0; + self->allocated_size = 0; +} + +usize asm_get_size(Asm *self) { + return self->code_it - (u8*)self->code; } +#if 0 static void asm_print_code_hex(Asm *self) { u8 *ptr; int off; @@ -196,13 +205,14 @@ static void asm_print_code_hex(Asm *self) { if(off != 0) putc('\n', stdout); } +#endif int asm_execute(Asm *self) { void (*func)(); - if(mprotect(self->code, self->size, PROT_READ | PROT_EXEC) != 0) + if(mprotect(self->code, self->allocated_size, PROT_READ | PROT_EXEC) != 0) return -errno; - asm_print_code_hex(self); + /*asm_print_code_hex(self);*/ /* TODO: Verify if this is valid on all platforms. According to ISO C standard it isn't? */ *(void**)(&func) = self->code; @@ -214,17 +224,17 @@ int asm_execute(Asm *self) { static CHECK_RESULT int asm_ensure_capacity(Asm *self, usize size) { usize current_offset; current_offset = (u8*)self->code_it - (u8*)self->code; - if(current_offset + size > self->size) { + if(current_offset + size > self->allocated_size) { void *new_mem; usize new_size; - new_size = self->size + am_pagesize(); + new_size = self->allocated_size + am_pagesize(); new_mem = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(self->code == MAP_FAILED) return -errno; - am_memcpy(new_mem, self->code, self->size); + am_memcpy(new_mem, self->code, self->allocated_size); self->code = new_mem; - self->size = new_size; + self->allocated_size = new_size; self->code_it = (u8*)self->code + current_offset; } return 0; @@ -232,7 +242,7 @@ static CHECK_RESULT int asm_ensure_capacity(Asm *self, usize size) { #ifdef DEBUG static isize asm_get_capacity_left(Asm *self) { - return (isize)self->size - (isize)((u8*)self->code_it - (u8*)self->code); + return (isize)self->allocated_size - (isize)((u8*)self->code_it - (u8*)self->code); } #endif @@ -346,21 +356,20 @@ int asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) { return 0; } +/* Note: This shows as instruction movabs in intel assembly format */ 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); + ins_end(self, "mov %s, 0x%x", 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; @@ -371,7 +380,6 @@ int asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) { 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; @@ -382,7 +390,6 @@ int asm_add_rr(Asm *self, Reg64 dst, Reg64 src) { 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; @@ -393,7 +400,6 @@ int asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) { 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; @@ -403,6 +409,25 @@ int asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) { return 0; } +int asm_cqo(Asm *self) { + ins_start(self); + return_if_error(asm_ensure_capacity(self, 2)); + *self->code_it++ = REX_W; + *self->code_it++ = 0x99; + ins_end(self, "cqo"); + return 0; +} + +int asm_idiv_rr(Asm *self, Reg64 src) { + ins_start(self); + return_if_error(asm_ensure_capacity(self, 4)); + *self->code_it++ = REX_W; + *self->code_it++ = 0xF7; + asm_rr(self, src, 0x7); + ins_end(self, "idiv %s", reg64_to_str(src)); + return 0; +} + int asm_pushr(Asm *self, Reg64 reg) { ins_start(self); return_if_error(asm_ensure_capacity(self, 1)); @@ -419,6 +444,26 @@ int asm_popr(Asm *self, Reg64 reg) { return 0; } +/* + Note: This is sometimes called with @relative 0 (will print call -5), in which case it's most likely a dummy call until the relative position + is later changed with @asm_override_call_rel32. TODO: Update the ins_end debug print to take that into account somehow +*/ +int asm_call_rel32(Asm *self, i32 relative) { + ins_start(self); + relative -= 5; /* In x86, the relative position starts from the next instruction */ + return_if_error(asm_ensure_capacity(self, 5)); + *self->code_it++ = 0xE8; + am_memcpy(self->code_it, &relative, sizeof(relative)); + self->code_it += sizeof(relative); + ins_end(self, "call 0x%x", relative); + return 0; +} + +void asm_override_call_rel32(Asm *self, u32 asm_index, i32 new_relative) { + new_relative -= 5; /* In x86, the relative position starts from the next instruction */ + am_memcpy((u8*)self->code + asm_index + 1, &new_relative, sizeof(new_relative)); +} + /* TODO: Remove these !*/ /* /r */ @@ -559,11 +604,12 @@ int asm_ret(Asm *self, u16 bytes) { if(bytes == 0) { return_if_error(asm_ensure_capacity(self, 1)); *self->code_it++ = 0xC3; + ins_end(self, "ret"); } else { return_if_error(asm_ensure_capacity(self, 3)); *self->code_it++ = 0xC2; am_memcpy(self->code_it, &bytes, sizeof(bytes)); + ins_end(self, "ret 0x%x", bytes); } - ins_end(self, "ret 0x%x", bytes); return 0; } |