aboutsummaryrefslogtreecommitdiff
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/executor.h2
-rw-r--r--executor/x86_64/asm.c11
-rw-r--r--executor/x86_64/asm.h1
-rw-r--r--executor/x86_64/executor.c45
4 files changed, 54 insertions, 5 deletions
diff --git a/executor/executor.h b/executor/executor.h
index 70d9637..2ef4995 100644
--- a/executor/executor.h
+++ b/executor/executor.h
@@ -43,8 +43,8 @@ CHECK_RESULT int amal_exec_pushd(amal_executor *self, BufferView data);
CHECK_RESULT int amal_exec_call_start(amal_executor *self, u8 num_args);
CHECK_RESULT int amal_exec_call(amal_executor *self, u32 code_offset, AmalReg dst_reg);
void amal_exec_call_overwrite(amal_executor *self, u32 call_code_offset, i32 new_target_rel32);
-/*CHECK_RESULT int amal_exec_callr(AmalReg dst_reg, BufferView data);*/
CHECK_RESULT int amal_exec_calle(amal_executor *self, void *func, AmalReg dst_reg);
+CHECK_RESULT int amal_exec_callr(amal_executor *self, AmalReg reg, AmalReg dst_reg);
CHECK_RESULT int amal_exec_eq(amal_executor *self, AmalReg dst_reg, AmalReg src_reg1, AmalReg src_reg2);
CHECK_RESULT int amal_exec_neq(amal_executor *self, AmalReg dst_reg, AmalReg src_reg1, AmalReg src_reg2);
CHECK_RESULT int amal_exec_ilt(amal_executor *self, AmalReg dst_reg, AmalReg src_reg1, AmalReg src_reg2);
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c
index a400656..cf56b69 100644
--- a/executor/x86_64/asm.c
+++ b/executor/x86_64/asm.c
@@ -70,6 +70,7 @@ static void ins_end(Asm *self, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
+ fprintf(stderr, "%06x | ", (unsigned int)ins_start_offset);
ins_end_offset = (u8*)self->code_it - (u8*)self->code;
for(i = ins_start_offset; i < ins_end_offset; ++i) {
fprintf(stderr, "%02x ", ((u8*)self->code)[i]);
@@ -145,6 +146,8 @@ static const char* asm_ptr_to_string(AsmPtr *self) {
return buf;
}
#else
+#include <stdarg.h>
+
static void ins_start(Asm *self) {
(void)self;
}
@@ -478,6 +481,14 @@ void asm_callr(Asm *self, Reg64 reg) {
ins_end(self, "call %s", reg64_to_str(reg));
}
+void asm_callm(Asm *self, AsmPtr *ptr) {
+ ins_start(self);
+ *self->code_it++ = rex_rm(ptr, 0);
+ *self->code_it++ = 0xFF;
+ asm_rm(self, ptr, 0x2);
+ ins_end(self, "call %s", asm_ptr_to_string(ptr));
+}
+
/*
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_overwrite_call_rel32. TODO: Update the ins_end debug print to take that into account somehow
diff --git a/executor/x86_64/asm.h b/executor/x86_64/asm.h
index 7d68bc0..355e133 100644
--- a/executor/x86_64/asm.h
+++ b/executor/x86_64/asm.h
@@ -96,6 +96,7 @@ void asm_idiv_rax_r(Asm *self, Reg64 src);
void asm_pushr(Asm *self, Reg64 reg);
void asm_popr(Asm *self, Reg64 reg);
void asm_callr(Asm *self, Reg64 reg);
+void asm_callm(Asm *self, AsmPtr *ptr);
/*
In x86 assembly, the @relative position starts from the next instruction.
This offset shouldn't be calculated by the caller and is instead managed
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c
index 65f8baa..378bc31 100644
--- a/executor/x86_64/executor.c
+++ b/executor/x86_64/executor.c
@@ -136,6 +136,17 @@ static void asm_cmp(Asm *self, AsmOperand *op1, AsmOperand *op2) {
}
}
+static void asm_call(Asm *self, AsmOperand *op) {
+ switch(op->type) {
+ case OPERAND_TYPE_REG:
+ asm_callr(self, op->value.reg);
+ break;
+ case OPERAND_TYPE_MEM:
+ asm_callm(self, &op->value.mem);
+ break;
+ }
+}
+
int amal_executor_init(amal_executor **self) {
amal_executor_impl **impl;
impl = (amal_executor_impl**)self;
@@ -388,7 +399,7 @@ int amal_exec_call(amal_executor *self, u32 code_offset, AmalReg dst_reg) {
/* 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);
+ isize asm_offset;
/* TODO: Do not push */
int num_pushed_stack = impl->num_pushed_values;/* + impl->num_saved_params_for_call - (int)NUM_REG_PARAMS;*/
ASM_ENSURE_CAPACITY
@@ -398,6 +409,7 @@ int amal_exec_call(amal_executor *self, u32 code_offset, AmalReg dst_reg) {
++num_pushed_stack;
asm_sub_rm64_imm(&impl->asm, RSP, sizeof(isize));
}
+ asm_offset = asm_get_size(&impl->asm);
assert(code_offset < asm_offset);
asm_call_rel32(&impl->asm, (isize)code_offset - asm_offset);
@@ -453,11 +465,36 @@ int amal_exec_calle(amal_executor *self, void *func, AmalReg dst_reg) {
return 0;
}
-/*
-int amal_exec_callr(AmalReg dst_reg, BufferView data) {
+int amal_exec_callr(amal_executor *self, AmalReg reg, AmalReg dst_reg) {
+ amal_executor_impl *impl = (amal_executor_impl*)self;
+ /* TODO: Preserve necessary registers before call? */
+ /* TODO: This assumes all arguments are isize */
+ /* TODO: Do not push */
+ int num_pushed_stack = impl->num_pushed_values;/* + impl->num_saved_params_for_call - (int)NUM_REG_PARAMS;*/
+ AsmOperand func_ptr_op;
+ ASM_ENSURE_CAPACITY
+
+ /*assert((num_pushed_stack <= 0 || num_pushed_stack % 2 == 0) && "TODO: Align stack to 16-bytes before calling functions");*/
+ if(num_pushed_stack & 1) {
+ ++num_pushed_stack;
+ asm_sub_rm64_imm(&impl->asm, RSP, sizeof(isize));
+ }
+ func_ptr_op = amal_reg_to_asm_operand(reg);
+ asm_call(&impl->asm, &func_ptr_op);
+ /* Function result */
+ {
+ AsmOperand dst_op = amal_reg_to_asm_operand(dst_reg);
+ AsmOperand rax_op = asm_reg_to_operand(RAX);
+ /* TODO: Make this work when result is not stored in RAX (multiple return results) */
+ asm_mov(&impl->asm, &dst_op, &rax_op);
+ }
+ /* Function cleanup */
+ if(num_pushed_stack > 0)
+ asm_add_rm64_imm(&impl->asm, RSP, num_pushed_stack * sizeof(isize));
+ impl->num_pushed_values = 0;
+ return 0;
}
-*/
int amal_exec_eq(amal_executor *self, AmalReg dst_reg, AmalReg src_reg1, AmalReg src_reg2) {
AsmOperand dst_op = amal_reg_to_asm_operand(dst_reg);