diff options
Diffstat (limited to 'executor/x86_64')
-rw-r--r-- | executor/x86_64/asm.c | 34 | ||||
-rw-r--r-- | executor/x86_64/asm.h | 8 | ||||
-rw-r--r-- | executor/x86_64/executor.c | 77 |
3 files changed, 45 insertions, 74 deletions
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c index c2b00ef..e29130e 100644 --- a/executor/x86_64/asm.c +++ b/executor/x86_64/asm.c @@ -218,24 +218,22 @@ int asm_execute(Asm *self, u32 offset) { /*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 + offset; + *(void**)(&func) = (u8*)self->code + offset; func(); return 0; } /* TODO: See how this can be optimized */ int asm_ensure_capacity(Asm *self, usize size) { - usize current_offset; - current_offset = (u8*)self->code_it - (u8*)self->code; + usize current_offset = (u8*)self->code_it - (u8*)self->code; if(current_offset + size > self->allocated_size) { - void *new_mem; - usize new_size; - 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) + usize new_size = self->allocated_size + am_pagesize(); + void *new_mem = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if(new_mem == MAP_FAILED) return -errno; am_memcpy(new_mem, self->code, self->allocated_size); + munmap(self->code, self->allocated_size); self->code = new_mem; self->allocated_size = new_size; self->code_it = (u8*)self->code + current_offset; @@ -435,7 +433,7 @@ void asm_callr(Asm *self, Reg64 reg) { /* 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 + is later changed with @asm_overwrite_call_rel32. TODO: Update the ins_end debug print to take that into account somehow */ void asm_call_rel32(Asm *self, i32 relative) { ins_start(self); @@ -446,8 +444,8 @@ void asm_call_rel32(Asm *self, i32 relative) { ins_end(self, "call 0x%x", relative); } -void asm_override_call_rel32(Asm *self, u32 asm_index, i32 new_relative) { - assert(*(u8*)(self->code + asm_index) == 0xE8); +void asm_overwrite_call_rel32(Asm *self, u32 asm_index, i32 new_relative) { + assert(*((u8*)self->code + asm_index) == 0xE8); 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)); } @@ -480,7 +478,7 @@ void asm_sete_r(Asm *self, Reg64 dst) { /* Note: This is sometimes called with @relative INT32_MAX-(2 or 6) (will print jz 0x7ffffff9), in which case it's most likely a dummy - jump until the relative position is later changed with @asm_override_jcc_rel32. + jump until the relative position is later changed with @asm_overwrite_jcc_rel32. TODO: Update the ins_end debug print to take that into account somehow */ void asm_jz(Asm *self, i32 relative) { @@ -503,17 +501,17 @@ void asm_jz(Asm *self, i32 relative) { ins_end(self, "jz 0x%x", relative); } -void asm_override_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative) { +void asm_overwrite_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative) { /* +2 because rel32 variant of the jump instruction opcode is 2 bytes */ - assert(*(u8*)(self->code + asm_index) == 0x0F); - assert(*(u8*)(self->code + asm_index + 1) == 0x84); + assert(*((u8*)self->code + asm_index) == 0x0F); + assert(*((u8*)self->code + asm_index + 1) == 0x84); new_relative -= 6; /* In x86, the relative position starts from the next instruction */ am_memcpy((u8*)self->code + asm_index + 2, &new_relative, sizeof(new_relative)); } /* Note: This is sometimes called with @relative INT32_MAX-(2 or 5) (will print jmp 0x7ffffffa), in which case it's most likely a dummy - jump until the relative position is later changed with @asm_override_jmp_rel32. + jump until the relative position is later changed with @asm_overwrite_jmp_rel32. TODO: Update the ins_end debug print to take that into account somehow */ void asm_jmp(Asm *self, i32 relative) { @@ -535,9 +533,9 @@ void asm_jmp(Asm *self, i32 relative) { ins_end(self, "jmp 0x%x", relative); } -void asm_override_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative) { +void asm_overwrite_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative) { /* +1 to skip instruction opcode */ - assert(*(u8*)(self->code + asm_index) == 0xE9); + assert(*((u8*)self->code + asm_index) == 0xE9); 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)); } diff --git a/executor/x86_64/asm.h b/executor/x86_64/asm.h index a3f1b5a..6ac74f4 100644 --- a/executor/x86_64/asm.h +++ b/executor/x86_64/asm.h @@ -88,7 +88,7 @@ void asm_callr(Asm *self, Reg64 reg); by this asm library itself. */ void asm_call_rel32(Asm *self, i32 relative); -void asm_override_call_rel32(Asm *self, u32 asm_index, i32 new_relative); +void asm_overwrite_call_rel32(Asm *self, u32 asm_index, i32 new_relative); void asm_cmp_rm(Asm *self, Reg64 reg1, AsmPtr *reg2); /* @@ -104,15 +104,15 @@ void asm_sete_r(Asm *self, Reg64 dst); by this asm library itself. */ void asm_jz(Asm *self, i32 relative); -/* Override conditional jump target */ -void asm_override_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative); +/* Overwrite conditional jump target */ +void asm_overwrite_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative); /* In x86 assembly, the @relative position starts from the next instruction. This offset shouldn't be calculated by the caller and is instead managed by this asm library itself. */ void asm_jmp(Asm *self, i32 relative); -void asm_override_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative); +void asm_overwrite_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative); diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c index 9083e14..c442da8 100644 --- a/executor/x86_64/executor.c +++ b/executor/x86_64/executor.c @@ -1,6 +1,7 @@ #include "../executor.h" #include "../../include/std/alloc.h" #include "../../include/std/buffer.h" +#include "../../include/std/log.h" #include "asm.h" #include <assert.h> @@ -19,29 +20,23 @@ typedef struct { u32 asm_index; - u16 func_index; -} CallDefer; - -typedef struct { - u32 asm_index; u16 target_label; bool condition; } JumpDefer; typedef struct { Asm asm; - usize *function_indices; - u16 num_functions; u16 func_counter; - Buffer/*CallDefer*/ call_defer; Buffer/*JumpDefer*/ jump_defer; u32 label_asm_index[MAX_LABELS]; int label_counter; } amal_executor_impl; +#define ASM_ENSURE_CAPACITY return_if_error(asm_ensure_capacity(&impl->asm, 256)); + #define IMPL_START \ amal_executor_impl *impl = (amal_executor_impl*)self; \ - return_if_error(asm_ensure_capacity(&impl->asm, 256)); + ASM_ENSURE_CAPACITY /* @reg will be a positive value when accessing local variables, in which case the first @@ -64,10 +59,7 @@ int amal_executor_init(amal_executor **self) { impl = (amal_executor_impl**)self; *impl = NULL; return_if_error(am_malloc(sizeof(amal_executor_impl), (void**)impl)); - (*impl)->function_indices = NULL; - (*impl)->num_functions = 0; (*impl)->func_counter = 0; - ignore_result_int(buffer_init(&(*impl)->call_defer, NULL)); ignore_result_int(buffer_init(&(*impl)->jump_defer, NULL)); (*impl)->label_counter = 0; return asm_init(&(*impl)->asm); @@ -76,8 +68,6 @@ int amal_executor_init(amal_executor **self) { void amal_executor_deinit(amal_executor *self) { amal_executor_impl *impl = (amal_executor_impl*)self; buffer_deinit(&impl->jump_defer); - buffer_deinit(&impl->call_defer); - am_free(impl->function_indices); asm_deinit(&impl->asm); am_free(impl); } @@ -93,26 +83,13 @@ u32 amal_exec_get_code_offset(amal_executor *self) { } int amal_executor_instructions_start(amal_executor *self, u16 num_functions) { - amal_executor_impl *impl = (amal_executor_impl*)self; - return_if_error(am_realloc(impl->function_indices, num_functions * sizeof(usize), (void**)&impl->function_indices)); - impl->num_functions = num_functions; + (void)self; + (void)num_functions; return 0; } int amal_executor_instructions_end(amal_executor *self) { amal_executor_impl *impl = (amal_executor_impl*)self; - CallDefer *call_defer = buffer_begin(&impl->call_defer); - CallDefer *call_defer_end = buffer_end(&impl->call_defer); - for(; call_defer != call_defer_end; ++call_defer) { - i32 func_offset; - if(call_defer->func_index >= impl->num_functions) { - amal_log_error("Program attempted to call a function that doesn't exist (index %u, while there are only %u functions)", call_defer->func_index, impl->num_functions); - return -1; - } - func_offset = (isize)impl->function_indices[call_defer->func_index] - (isize)call_defer->asm_index; - asm_override_call_rel32(&impl->asm, call_defer->asm_index, func_offset); - } - buffer_clear(&impl->call_defer); impl->func_counter = 0; return 0; } @@ -299,25 +276,16 @@ int amal_exec_pushd(amal_executor *self, BufferView data) { return 0; } -int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args, i8 dst_reg) { - IMPL_START +int amal_exec_call(amal_executor *self, u32 code_offset, u8 num_args, i8 dst_reg) { + amal_executor_impl *impl = (amal_executor_impl*)self; /* TODO: Preserve necessary registers before call? */ /* TODO: This assumes all arguments are isize */ /* Do the function call */ isize asm_offset = asm_get_size(&impl->asm); - if(func_index < impl->func_counter) { - asm_call_rel32(&impl->asm, (isize)impl->function_indices[func_index] - asm_offset); - } else { - /* - The location of the function has not been defined yet. Use call instruction with dummy data and change - the location once the location to the function is known - */ - CallDefer call_defer; - call_defer.asm_index = asm_offset; - call_defer.func_index = func_index; - return_if_error(buffer_append(&impl->call_defer, &call_defer, sizeof(call_defer))); - asm_call_rel32(&impl->asm, 0); - } + ASM_ENSURE_CAPACITY + + assert(code_offset < asm_offset); + asm_call_rel32(&impl->asm, (isize)code_offset - asm_offset); /* Handle function result and cleanup */ { @@ -331,6 +299,11 @@ int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args, i8 dst_reg) return 0; } +void amal_exec_call_overwrite(amal_executor *self, u32 call_code_offset, i32 new_target_rel32) { + amal_executor_impl *impl = (amal_executor_impl*)self; + asm_overwrite_call_rel32(&impl->asm, call_code_offset, new_target_rel32); +} + const Reg64 SYS_V_PARAM_REGS[] = { RDI, RSI, RDX, RCX }; /* @@ -379,9 +352,9 @@ int amal_exec_callr(i8 dst_reg, BufferView data) { */ int amal_exec_cmp(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) { + AsmPtr dst, src1, src2; IMPL_START - AsmPtr dst, src1, src2; asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg)); asm_ptr_init_disp(&src1, RBP, get_register_stack_offset(src_reg1)); asm_ptr_init_disp(&src2, RBP, get_register_stack_offset(src_reg2)); @@ -424,8 +397,9 @@ int amal_exec_jz(amal_executor *self, i8 reg, u16 target_label) { } int amal_exec_jmp(amal_executor *self, u16 target_label) { - IMPL_START + amal_executor_impl *impl = (amal_executor_impl*)self; u32 asm_offset = asm_get_size(&impl->asm); + ASM_ENSURE_CAPACITY if(target_label < impl->label_counter) { asm_jmp(&impl->asm, (i32)impl->label_asm_index[target_label] - (i32)asm_offset); return 0; @@ -466,7 +440,6 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) { 64-bit Linux,BSD,Mac: RBX, RBP, R12-R15 */ IMPL_START - impl->function_indices[impl->func_counter++] = asm_get_size(&impl->asm); asm_pushr(&impl->asm, RBX); asm_pushr(&impl->asm, RBP); asm_mov_rr(&impl->asm, RBP, RSP); @@ -475,10 +448,10 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) { } int amal_exec_func_end(amal_executor *self) { - IMPL_START - + amal_executor_impl *impl = (amal_executor_impl*)self; JumpDefer *jump_defer = buffer_begin(&impl->jump_defer); JumpDefer *jump_defer_end = buffer_end(&impl->jump_defer); + ASM_ENSURE_CAPACITY for(; jump_defer != jump_defer_end; ++jump_defer) { i32 jump_offset; if(jump_defer->target_label >= impl->label_counter) { @@ -487,9 +460,9 @@ int amal_exec_func_end(amal_executor *self) { } jump_offset = (isize)impl->label_asm_index[jump_defer->target_label] - (isize)jump_defer->asm_index; if(jump_defer->condition) - asm_override_jcc_rel32(&impl->asm, jump_defer->asm_index, jump_offset); + asm_overwrite_jcc_rel32(&impl->asm, jump_defer->asm_index, jump_offset); else - asm_override_jmp_rel32(&impl->asm, jump_defer->asm_index, jump_offset); + asm_overwrite_jmp_rel32(&impl->asm, jump_defer->asm_index, jump_offset); } buffer_clear(&impl->jump_defer); impl->label_counter = 0; @@ -502,7 +475,7 @@ int amal_exec_func_end(amal_executor *self) { } int amal_exec_label(amal_executor *self) { - IMPL_START + amal_executor_impl *impl = (amal_executor_impl*)self; assert(impl->label_counter < MAX_LABELS); impl->label_asm_index[impl->label_counter++] = asm_get_size(&impl->asm); return 0; |