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.c93
1 files changed, 75 insertions, 18 deletions
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c
index b7aa91f..ebe848d 100644
--- a/executor/x86_64/executor.c
+++ b/executor/x86_64/executor.c
@@ -28,7 +28,16 @@ typedef struct {
amal_executor_impl *impl; \
impl = (amal_executor_impl*)self;
-#define get_register_stack_offset(reg) -(i32)(reg * (int)sizeof(usize) + (int)sizeof(usize))
+/*
+ @reg will be a positive value when accessing local variables, in which case the first
+ local variable is located at -sizeof(usize) and the next one is at -(2 * sizeof(usize)).
+ @reg will be a negative value starting at -1 when accessing parameters.
+ The first parameter is located at 3*sizeof(usize) and the next one is at 4*sizeof(usize).
+ Parameter starts at 3*sizeof(usize) because offset 0 is the return address, offset 1*sizeof(usize) is the
+ saved RBP and 2*sizeof(usize) is saved RBX.
+*/
+#define get_register_stack_offset(reg) \
+ (reg >= 0 ? (i32)(-reg * (int)sizeof(usize) - sizeof(usize)) : (i32)(-reg * (int)sizeof(usize) + 2*sizeof(usize)))
static i64 abs_i64(i64 value) {
return value >= 0 ? value : -value;
@@ -88,14 +97,14 @@ int amal_exec_nop(amal_executor *self) {
return asm_nop(&impl->asm);
}
-int amal_exec_setz(amal_executor *self, u8 dst_reg) {
+int amal_exec_setz(amal_executor *self, i8 dst_reg) {
AsmPtr dst;
IMPL
asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg));
return asm_mov_mi(&impl->asm, &dst, 0);
}
-int amal_exec_mov(amal_executor *self, u8 dst_reg, u8 src_reg) {
+int amal_exec_mov(amal_executor *self, i8 dst_reg, i8 src_reg) {
AsmPtr ptr;
IMPL
@@ -106,7 +115,7 @@ int amal_exec_mov(amal_executor *self, u8 dst_reg, u8 src_reg) {
return asm_mov_mr(&impl->asm, &ptr, RAX);
}
-int amal_exec_movi(amal_executor *self, u8 dst_reg, i64 imm) {
+int amal_exec_movi(amal_executor *self, i8 dst_reg, i64 imm) {
IMPL
/* TODO: if @number is a float then use float instructions */
if(abs_i64(imm) <= INT32_MAX) {
@@ -122,7 +131,7 @@ int amal_exec_movi(amal_executor *self, u8 dst_reg, i64 imm) {
return 0;
}
-int amal_exec_movd(amal_executor *self, u8 dst_reg, BufferView data) {
+int amal_exec_movd(amal_executor *self, i8 dst_reg, BufferView data) {
AsmPtr dst;
IMPL
@@ -131,7 +140,7 @@ int amal_exec_movd(amal_executor *self, u8 dst_reg, BufferView data) {
return asm_mov_mr(&impl->asm, &dst, RAX);
}
-int amal_exec_add(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
+int amal_exec_add(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
AsmPtr dst;
AsmPtr reg1;
AsmPtr reg2;
@@ -147,7 +156,7 @@ int amal_exec_add(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return asm_mov_mr(&impl->asm, &dst, RAX);
}
-int amal_exec_sub(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
+int amal_exec_sub(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
AsmPtr dst;
AsmPtr reg1;
AsmPtr reg2;
@@ -163,7 +172,7 @@ int amal_exec_sub(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return asm_mov_mr(&impl->asm, &dst, RAX);
}
-int amal_exec_imul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
+int amal_exec_imul(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
AsmPtr dst;
AsmPtr reg1;
AsmPtr reg2;
@@ -179,7 +188,7 @@ int amal_exec_imul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return asm_mov_mr(&impl->asm, &dst, RAX);
}
-int amal_exec_mul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
+int amal_exec_mul(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
(void)self;
(void)dst_reg;
(void)src_reg1;
@@ -203,7 +212,7 @@ int amal_exec_mul(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return 0;
}
-int amal_exec_idiv(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
+int amal_exec_idiv(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
AsmPtr dst;
AsmPtr reg1;
AsmPtr reg2;
@@ -216,11 +225,12 @@ int amal_exec_idiv(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return_if_error(asm_mov_rm(&impl->asm, RAX, &reg1));
return_if_error(asm_mov_rm(&impl->asm, RCX, &reg2));
return_if_error(asm_cqo(&impl->asm));
+ /* TODO: Preserve RDX if needed, since it's also used as a parameter in system-v x86_64 abi */
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) {
+int amal_exec_div(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
(void)self;
(void)dst_reg;
(void)src_reg1;
@@ -230,7 +240,7 @@ int amal_exec_div(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return 0;
}
-int amal_exec_push(amal_executor *self, u8 reg) {
+int amal_exec_push(amal_executor *self, i8 reg) {
AsmPtr reg_ptr;
IMPL
@@ -255,7 +265,7 @@ int amal_exec_pushd(amal_executor *self, BufferView data) {
return 0;
}
-int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args) {
+int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args, i8 dst_reg) {
isize asm_size;
IMPL
/* TODO: Preserve necessary registers before call? */
@@ -275,18 +285,65 @@ int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args) {
return_if_error(asm_call_rel32(&impl->asm, 0));
}
+ {
+ AsmPtr dst;
+ asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg));
+ /* TODO: Make this work when result is not stored in RAX (multiple return results) */
+ return_if_error(asm_mov_mr(&impl->asm, &dst, RAX));
+ }
+ if(num_args > 0)
+ return asm_add_rm64_imm(&impl->asm, RSP, num_args * sizeof(isize));
+ return 0;
+}
+
+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.
+ System-V ABI parameters:
+ RDI, RSI, RDX, RCX, R8, R9, XMM0–7.
+ 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) {
+ AsmPtr dst;
+ IMPL
+
+ /* TODO: Support R and XMM registers so more than 5 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) {
+ return_if_error(asm_mov_rm(&impl->asm, SYS_V_PARAM_REGS[i], &src));
+ src.disp += 0x8;
+ }
+ }
+
+ /* TODO: Preserve necessary registers before call? */
+ /* TODO: This assumes all arguments are isize */
+ return_if_error(asm_mov_ri(&impl->asm, RAX, (intptr_t)func));
+ return_if_error(asm_callr(&impl->asm, RAX));
+ asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg));
+ return_if_error(asm_mov_mr(&impl->asm, &dst, RAX));
if(num_args > 0)
return asm_add_rm64_imm(&impl->asm, RSP, num_args * sizeof(isize));
return 0;
}
/*
-int amal_exec_callr(u8 dst_reg, BufferView data) {
+int amal_exec_callr(i8 dst_reg, BufferView data) {
}
*/
-int amal_exec_cmp(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
+int amal_exec_cmp(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
(void)self;
(void)dst_reg;
(void)src_reg1;
@@ -296,7 +353,7 @@ int amal_exec_cmp(amal_executor *self, u8 dst_reg, u8 src_reg1, u8 src_reg2) {
return 0;
}
-int amal_exec_jz(amal_executor *self, u8 dst_reg, i16 offset) {
+int amal_exec_jz(amal_executor *self, i8 dst_reg, i16 offset) {
(void)self;
(void)dst_reg;
(void)offset;
@@ -313,12 +370,12 @@ int amal_exec_jmp(amal_executor *self, i16 offset) {
return 0;
}
-int amal_exec_ret(amal_executor *self, u8 reg) {
+int amal_exec_ret(amal_executor *self, i8 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 */
+ /* Result is returned in RAX register. TODO: Make this work when returning more than one result */
return_if_error(asm_mov_rm(&impl->asm, RAX, &ret_reg));
return amal_exec_func_end(self);
}