diff options
Diffstat (limited to 'executor/x86_64/executor.c')
-rw-r--r-- | executor/x86_64/executor.c | 129 |
1 files changed, 110 insertions, 19 deletions
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c index b53ccea..b7aa91f 100644 --- a/executor/x86_64/executor.c +++ b/executor/x86_64/executor.c @@ -1,5 +1,6 @@ #include "../executor.h" #include "../../include/std/alloc.h" +#include "../../include/std/buffer.h" #include "asm.h" #include <assert.h> @@ -11,7 +12,16 @@ */ typedef struct { + u32 asm_index; + u16 func_index; +} CallDefer; + +typedef struct { Asm asm; + usize *function_indices; + u16 num_functions; + u16 func_counter; + Buffer/*CallDefer*/ call_defer; } amal_executor_impl; #define IMPL \ @@ -26,13 +36,20 @@ static i64 abs_i64(i64 value) { int amal_executor_init(amal_executor **self) { amal_executor_impl **impl; - return_if_error(am_malloc(sizeof(amal_executor_impl), (void**)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)); return asm_init(&(*impl)->asm); } void amal_executor_deinit(amal_executor *self) { IMPL + buffer_deinit(&impl->call_defer); + am_free(impl->function_indices); asm_deinit(&impl->asm); am_free(impl); } @@ -42,6 +59,30 @@ int amal_executor_run(amal_executor *self) { return asm_execute(&impl->asm); } +int amal_executor_instructions_start(amal_executor *self, u16 num_functions) { + void *new_data; + IMPL + return_if_error(am_realloc(impl->function_indices, num_functions * sizeof(*impl->function_indices), &new_data)); + impl->function_indices = new_data; + impl->num_functions = num_functions; + impl->func_counter = 0; + buffer_clear(&impl->call_defer); + return 0; +} + +int amal_executor_instructions_end(amal_executor *self) { + CallDefer *call_defer, *call_defer_end; + IMPL + + call_defer = buffer_begin(&impl->call_defer); + call_defer_end = buffer_end(&impl->call_defer); + for(; call_defer != call_defer_end; ++call_defer) { + const isize 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); + } + return 0; +} + int amal_exec_nop(amal_executor *self) { IMPL return asm_nop(&impl->asm); @@ -158,16 +199,25 @@ int amal_exec_mul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { return_if_error(asm_mul_rr(&self->asm, RAX, RCX)); return_if_error(asm_mov_mr(&self->asm, &dst, RAX)); #endif + assert(bool_false && "TODO: Implement!"); return 0; } int amal_exec_idiv(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { - (void)self; - (void)dst_reg; - (void)src_reg1; - (void)src_reg2; - /* TODO: Implement! */ - return 0; + AsmPtr dst; + AsmPtr reg1; + AsmPtr reg2; + IMPL + + asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg)); + asm_ptr_init_disp(®1, RBP, get_register_stack_offset(src_reg1)); + asm_ptr_init_disp(®2, RBP, get_register_stack_offset(src_reg2)); + + return_if_error(asm_mov_rm(&impl->asm, RAX, ®1)); + return_if_error(asm_mov_rm(&impl->asm, RCX, ®2)); + return_if_error(asm_cqo(&impl->asm)); + return_if_error(asm_idiv_rr(&impl->asm, RCX)); + return asm_mov_mr(&impl->asm, &dst, RAX); } int amal_exec_div(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { @@ -176,20 +226,24 @@ int amal_exec_div(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { (void)src_reg1; (void)src_reg2; /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); return 0; } int amal_exec_push(amal_executor *self, u8 reg) { - (void)self; - (void)reg; - /* TODO: Implement! */ - return 0; + AsmPtr reg_ptr; + IMPL + + asm_ptr_init_disp(®_ptr, RBP, get_register_stack_offset(reg)); + return_if_error(asm_mov_rm(&impl->asm, RAX, ®_ptr)); + return asm_pushr(&impl->asm, RAX); } int amal_exec_pushi(amal_executor *self, i64 imm) { (void)self; (void)imm; /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); return 0; } @@ -197,17 +251,48 @@ int amal_exec_pushd(amal_executor *self, BufferView data) { (void)self; (void)data; /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); + return 0; +} + +int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args) { + isize asm_size; + IMPL + /* TODO: Preserve necessary registers before call? */ + /* TODO: This assumes all arguments are isize */ + asm_size = asm_get_size(&impl->asm); + if(func_index < impl->func_counter) { + return_if_error(asm_call_rel32(&impl->asm, (isize)impl->function_indices[func_index] - asm_size)); + } 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_size; + call_defer.func_index = func_index; + return_if_error(buffer_append(&impl->call_defer, &call_defer, sizeof(call_defer))); + return_if_error(asm_call_rel32(&impl->asm, 0)); + } + + if(num_args > 0) + return asm_add_rm64_imm(&impl->asm, RSP, num_args * sizeof(isize)); return 0; } -/*int amal_exec_call(u8 dst_reg, BufferView data); -int amal_exec_callr(u8 dst_reg, BufferView data);*/ +/* +int amal_exec_callr(u8 dst_reg, BufferView data) { + +} +*/ + int amal_exec_cmp(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) { (void)self; (void)dst_reg; (void)src_reg1; (void)src_reg2; /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); return 0; } @@ -216,6 +301,7 @@ int amal_exec_jz(amal_executor *self, u8 dst_reg, i16 offset) { (void)dst_reg; (void)offset; /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); return 0; } @@ -223,14 +309,18 @@ int amal_exec_jmp(amal_executor *self, i16 offset) { (void)self; (void)offset; /* TODO: Implement! */ + assert(bool_false && "TODO: Implement!"); return 0; } -int amal_exec_ret(amal_executor *self) { - (void)self; - /* TODO: Implement! */ - assert(bool_false && "TODO: Implement RET. RET needs to restore the stack before returning"); - return 0; +int amal_exec_ret(amal_executor *self, u8 reg) { + AsmPtr ret_reg; + IMPL + + asm_ptr_init_disp(&ret_reg, RBP, get_register_stack_offset(reg)); + /* Result is returned in RAX register. TODO: Make this work for larger data */ + return_if_error(asm_mov_rm(&impl->asm, RAX, &ret_reg)); + return amal_exec_func_end(self); } int amal_exec_func_start(amal_executor *self, u16 num_regs) { @@ -246,10 +336,11 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) { 64-bit Linux,BSD,Mac: RBX, RBP, R12-R15 */ IMPL + impl->function_indices[impl->func_counter++] = asm_get_size(&impl->asm); return_if_error(asm_pushr(&impl->asm, RBX)); return_if_error(asm_pushr(&impl->asm, RBP)); return_if_error(asm_mov_rr(&impl->asm, RBP, RSP)); - return asm_sub_rm64_imm(&impl->asm, RSP, num_regs * sizeof(usize)); + return asm_sub_rm64_imm(&impl->asm, RSP, num_regs * sizeof(isize)); } int amal_exec_func_end(amal_executor *self) { |