diff options
Diffstat (limited to 'executor')
-rw-r--r-- | executor/executor.h | 2 | ||||
-rw-r--r-- | executor/x86_64/asm.c | 11 | ||||
-rw-r--r-- | executor/x86_64/asm.h | 1 | ||||
-rw-r--r-- | executor/x86_64/executor.c | 45 |
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); |