diff options
Diffstat (limited to 'executor/x86_64/executor.c')
-rw-r--r-- | executor/x86_64/executor.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c index f747e4a..c918c13 100644 --- a/executor/x86_64/executor.c +++ b/executor/x86_64/executor.c @@ -30,6 +30,8 @@ typedef struct { Buffer/*JumpDefer*/ jump_defer; u32 label_asm_index[MAX_LABELS]; int label_counter; + int num_args; + int num_pushed_values; } amal_executor_impl; #define ASM_ENSURE_CAPACITY return_if_error(asm_ensure_capacity(&impl->asm, 256)); @@ -54,14 +56,19 @@ static i64 abs_i64(i64 value) { return value >= 0 ? value : -value; } +const Reg64 SYS_V_REG_PARAMS[] = { RDI, RSI, RDX, RCX, R8, R9, R10, R11 }; +const int NUM_REG_PARAMS = 8; + int amal_executor_init(amal_executor **self) { amal_executor_impl **impl; impl = (amal_executor_impl**)self; *impl = NULL; return_if_error(am_malloc(sizeof(amal_executor_impl), (void**)impl)); (*impl)->func_counter = 0; - ignore_result_int(buffer_init(&(*impl)->jump_defer, NULL)); (*impl)->label_counter = 0; + (*impl)->num_args = 0; + (*impl)->num_pushed_values = 0; + ignore_result_int(buffer_init(&(*impl)->jump_defer, NULL)); return asm_init(&(*impl)->asm); } @@ -234,7 +241,6 @@ int amal_exec_idiv(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) { asm_mov_rm(&impl->asm, RAX, ®1); asm_mov_rm(&impl->asm, RCX, ®2); asm_cqo(&impl->asm); - /* TODO: Preserve RDX if needed, since it's also used as a parameter in system-v x86_64 abi */ asm_idiv_rr(&impl->asm, RCX); asm_mov_mr(&impl->asm, &dst, RAX); return 0; @@ -255,8 +261,13 @@ int amal_exec_push(amal_executor *self, i8 reg) { IMPL_START asm_ptr_init_disp(®_ptr, RBP, get_register_stack_offset(reg)); - asm_mov_rm(&impl->asm, RAX, ®_ptr); - asm_pushr(&impl->asm, RAX); + if(impl->num_pushed_values < NUM_REG_PARAMS) { + asm_mov_rm(&impl->asm, SYS_V_REG_PARAMS[impl->num_pushed_values], ®_ptr); + } else { + asm_mov_rm(&impl->asm, RAX, ®_ptr); + asm_pushr(&impl->asm, RAX); + } + ++impl->num_pushed_values; return 0; } @@ -276,15 +287,22 @@ int amal_exec_pushd(amal_executor *self, BufferView data) { return 0; } -int amal_exec_call(amal_executor *self, u32 code_offset, u8 num_args, i8 dst_reg) { +int amal_exec_call_start(amal_executor *self, u8 num_args) { + amal_executor_impl *impl = (amal_executor_impl*)self; + impl->num_args = num_args; + return 0; +} + +int amal_exec_call(amal_executor *self, u32 code_offset, 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); + int num_pushed_stack = impl->num_pushed_values - (int)NUM_REG_PARAMS; ASM_ENSURE_CAPACITY - assert(num_args % 2 == 0 && "TODO: Align stack to 16-bytes before calling functions"); + assert((num_pushed_stack <= 0 || num_pushed_stack % 2 == 0) && "TODO: Align stack to 16-bytes before calling functions"); assert(code_offset < asm_offset); asm_call_rel32(&impl->asm, (isize)code_offset - asm_offset); @@ -295,8 +313,9 @@ int amal_exec_call(amal_executor *self, u32 code_offset, u8 num_args, i8 dst_reg /* TODO: Make this work when result is not stored in RAX (multiple return results) */ asm_mov_mr(&impl->asm, &dst, RAX); } - if(num_args > 0) - asm_add_rm64_imm(&impl->asm, RSP, num_args * sizeof(isize)); + if(num_pushed_stack > 0) + asm_add_rm64_imm(&impl->asm, RSP, num_pushed_stack * sizeof(isize)); + impl->num_pushed_values = 0; return 0; } @@ -305,8 +324,6 @@ void amal_exec_call_overwrite(amal_executor *self, u32 call_code_offset, i32 new asm_overwrite_call_rel32(&impl->asm, call_code_offset, new_target_rel32); } -const Reg64 SYS_V_PARAM_REGS[] = { RDI, RSI, RDX, RCX }; - /* TODO: Make argument passing work for different calling conventions and different ABI. This currently assumes x86_64 system v abi. @@ -315,26 +332,13 @@ const Reg64 SYS_V_PARAM_REGS[] = { RDI, RSI, RDX, RCX }; The rest are passed in the stack. */ /* TODO: Make this work when function returns something else than a POD */ -int amal_exec_calle(amal_executor *self, void *func, u8 num_args, i8 dst_reg) { +int amal_exec_calle(amal_executor *self, void *func, i8 dst_reg) { AsmPtr dst; - IMPL_START + amal_executor_impl *impl = (amal_executor_impl*)self; + int num_pushed_stack = impl->num_pushed_values - (int)NUM_REG_PARAMS; + ASM_ENSURE_CAPACITY - assert(num_args % 2 == 0 && "TODO: Align stack to 16-bytes before calling functions"); - /* TODO: Support R and XMM registers so more than 4 arguments can be used for functions */ - assert(num_args < 5); - { - /* - TODO: Do this directly in @PUSH instruction instead. For now we copy - the pushed data to the registers that need to be set for the specific abi for parameters - */ - int i; - AsmPtr src; - asm_ptr_init_disp(&src, RSP, 0); - for(i = num_args - 1; i >= 0; --i) { - asm_mov_rm(&impl->asm, SYS_V_PARAM_REGS[i], &src); - src.disp += 0x8; - } - } + assert((num_pushed_stack <= 0 || num_pushed_stack % 2 == 0) && "TODO: Align stack to 16-bytes before calling functions"); /* TODO: Preserve necessary registers before call? */ /* TODO: This assumes all arguments are isize */ @@ -342,8 +346,9 @@ int amal_exec_calle(amal_executor *self, void *func, u8 num_args, i8 dst_reg) { asm_callr(&impl->asm, RAX); asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg)); asm_mov_mr(&impl->asm, &dst, RAX); - if(num_args > 0) - asm_add_rm64_imm(&impl->asm, RSP, num_args * sizeof(isize)); + if(num_pushed_stack > 0) + asm_add_rm64_imm(&impl->asm, RSP, num_pushed_stack * sizeof(isize)); + impl->num_pushed_values = 0; return 0; } |