aboutsummaryrefslogtreecommitdiff
path: root/executor/x86_64/executor.c
diff options
context:
space:
mode:
Diffstat (limited to 'executor/x86_64/executor.c')
-rw-r--r--executor/x86_64/executor.c65
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, &reg1);
asm_mov_rm(&impl->asm, RCX, &reg2);
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(&reg_ptr, RBP, get_register_stack_offset(reg));
- asm_mov_rm(&impl->asm, RAX, &reg_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], &reg_ptr);
+ } else {
+ asm_mov_rm(&impl->asm, RAX, &reg_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;
}