diff options
Diffstat (limited to 'executor')
-rw-r--r-- | executor/executor.h | 5 | ||||
-rw-r--r-- | executor/x86_64/asm.c | 203 | ||||
-rw-r--r-- | executor/x86_64/asm.h | 28 | ||||
-rw-r--r-- | executor/x86_64/executor.c | 65 |
4 files changed, 174 insertions, 127 deletions
diff --git a/executor/executor.h b/executor/executor.h index 743500c..7f9793e 100644 --- a/executor/executor.h +++ b/executor/executor.h @@ -39,10 +39,11 @@ CHECK_RESULT int amal_exec_div(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 CHECK_RESULT int amal_exec_push(amal_executor *self, i8 reg); CHECK_RESULT int amal_exec_pushi(amal_executor *self, i64 imm); CHECK_RESULT int amal_exec_pushd(amal_executor *self, BufferView data); -CHECK_RESULT int amal_exec_call(amal_executor *self, u32 code_offset, u8 num_args, i8 dst_reg); +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, i8 dst_reg); void amal_exec_call_overwrite(amal_executor *self, u32 call_code_offset, i32 new_target_rel32); /*CHECK_RESULT int amal_exec_callr(i8 dst_reg, BufferView data);*/ -CHECK_RESULT int amal_exec_calle(amal_executor *self, void *func, u8 num_args, i8 dst_reg); +CHECK_RESULT int amal_exec_calle(amal_executor *self, void *func, i8 dst_reg); CHECK_RESULT int amal_exec_cmp(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2); CHECK_RESULT int amal_exec_jz(amal_executor *self, i8 reg, u16 target_label); CHECK_RESULT int amal_exec_jmp(amal_executor *self, u16 target_label); diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c index c633db8..60b1752 100644 --- a/executor/x86_64/asm.c +++ b/executor/x86_64/asm.c @@ -8,7 +8,31 @@ #include <sys/mman.h> -#define REX_W 0x48 +/* REX documentation: https://wiki.osdev.org/X86-64_Instruction_Encoding#Encoding */ +#define REX_W 0x48 /* 0 = 32-bit operand size, 1 = 64-bit operand size - For most operations... */ + +static u8 rex_rr(Reg64 dst, Reg64 src) { + u8 rex = REX_W; + rex |= ((dst & REG64_EXTENDED_REG_BIT) >> 3); /* REX.B */ + rex |= ((src & REG64_EXTENDED_REG_BIT) >> 1); /* REX.R */ + assert(REG64_EXTENDED_REG_BIT == (1<<3)); + return rex; +} + +static u8 rex_sib(Reg64 dst, Reg64 src) { + u8 rex = REX_W; + rex |= ((src & REG64_EXTENDED_REG_BIT) >> 3); /* REX.B */ + rex |= ((dst & REG64_EXTENDED_REG_BIT) >> 2); /* REX.X */ + assert(REG64_EXTENDED_REG_BIT == (1<<3)); + return rex; +} + +static u8 rex_rm(AsmPtr *dst, Reg64 src) { + assert(REG64_EXTENDED_REG_BIT == (1<<3)); + if(dst->index == 0 && (dst->base & REG64_REG_BITS) != RBP) + return rex_rr(dst->base, src); + return rex_sib(dst->base, src); +} #ifdef DEBUG #include <stdarg.h> @@ -84,6 +108,14 @@ static const char* reg64_to_str(Reg64 reg) { case RBP: return "rbp"; case RSI: return "rsi"; case RDI: return "rdi"; + case R8: return "r8"; + case R9: return "r9"; + case R10: return "r10"; + case R11: return "r11"; + case R12: return "r12"; + case R13: return "r13"; + case R14: return "r14"; + case R15: return "r15"; } assert(bool_false); return NULL; @@ -270,7 +302,7 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) { u8 rm_byte; u8 disp_bytes; assert(asm_get_capacity_left(self) >= 6); - if((int)mem->index != -1) { + if((int)mem->index != -1) { /* SIB */ u8 sib_offset; if(mem->disp == 0) { rm_byte = 0x04; @@ -293,31 +325,33 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) { } #endif assert(mem->base != RBP && "TODO: Implement RBP base for sib byte. RBP is special and requires different logic"); - sib_offset = (mem->scale << 5) + 8*mem->index + mem->base; + assert(mem->index != R13 && "TODO: Implement R13 base for sib byte. R13 is special and requires different logic"); + sib_offset = (mem->scale << 5) + 8*(mem->index & REG64_REG_BITS) + (mem->base & REG64_REG_BITS); *self->code_it++ = rm_byte; *self->code_it++ = sib_offset; } else { + u8 base = (mem->base & REG64_REG_BITS); assert(mem->scale == 0); /* Scale isn't valid without index reg */ if(mem->disp == 0) { - if(mem->base == RBP) { + if(base == RBP) { rm_byte = 0x45; - disp_bytes = 1; + disp_bytes = 1; /* RBP requires use of disp byte, even if it's not used */ } else { - rm_byte = mem->base; + rm_byte = base; disp_bytes = 0; } } else if(abs_i32(mem->disp) <= INT8_MAX) { - rm_byte = 0x40 + mem->base; + rm_byte = 0x40 + base; disp_bytes = 1; } else { - rm_byte = 0x80 + mem->base; + rm_byte = 0x80 + base; disp_bytes = 4; } - *self->code_it++ = (reg << 3) | rm_byte; + *self->code_it++ = ((reg & REG64_REG_BITS) << 3) | rm_byte; /* RSP requires SIB byte */ - if(mem->base == RSP) + if(base == RSP) *self->code_it++ = 0x24; } @@ -328,13 +362,13 @@ static void asm_rm(Asm *self, AsmPtr *mem, Reg64 reg) { /* There has to be at least 1 byte left in the asm buffer before calling this function. */ static void asm_rr(Asm *self, Reg64 dst, Reg64 src) { assert(asm_get_capacity_left(self) >= 1); - *self->code_it++ = 0xC0 + dst + 8*src; + *self->code_it++ = 0xC0 + (dst & REG64_REG_BITS) + 8*(src & REG64_REG_BITS); } /* TODO: Implement 1 and 2 byte immediate? */ void asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(dst, 0); *self->code_it++ = 0xC7; asm_rm(self, dst, 0); am_memcpy(self->code_it, &immediate, sizeof(immediate)); @@ -344,7 +378,7 @@ void asm_mov_mi(Asm *self, AsmPtr *dst, i32 immediate) { void asm_mov_mr(Asm *self, AsmPtr *dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(dst, src); *self->code_it++ = 0x89; asm_rm(self, dst, src); ins_end(self, "mov %s, %s", asm_ptr_to_string(dst), reg64_to_str(src)); @@ -352,7 +386,7 @@ void asm_mov_mr(Asm *self, AsmPtr *dst, Reg64 src) { void asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(src, dst); *self->code_it++ = 0x8B; asm_rm(self, src, dst); ins_end(self, "mov %s, %s", reg64_to_str(dst), asm_ptr_to_string(src)); @@ -361,7 +395,7 @@ void asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) { /* Note: This shows as instruction movabs in intel assembly format */ void asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, 0); *self->code_it++ = 0xB8 + dst; am_memcpy(self->code_it, &immediate, sizeof(immediate)); self->code_it += sizeof(immediate); @@ -370,7 +404,7 @@ void asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) { void asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x89; asm_rr(self, dst, src); ins_end(self, "mov %s, %s", reg64_to_str(dst), reg64_to_str(src)); @@ -378,7 +412,7 @@ void asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) { void asm_add_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x01; asm_rr(self, dst, src); ins_end(self, "add %s, %s", reg64_to_str(dst), reg64_to_str(src)); @@ -386,7 +420,7 @@ void asm_add_rr(Asm *self, Reg64 dst, Reg64 src) { void asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x29; asm_rr(self, dst, src); ins_end(self, "sub %s, %s", reg64_to_str(dst), reg64_to_str(src)); @@ -394,7 +428,7 @@ void asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) { void asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(dst, src); *self->code_it++ = 0x0F; *self->code_it++ = 0xAF; asm_rr(self, dst, src); @@ -410,7 +444,7 @@ void asm_cqo(Asm *self) { void asm_idiv_rr(Asm *self, Reg64 src) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(src, 0); *self->code_it++ = 0xF7; asm_rr(self, src, 0x7); ins_end(self, "idiv %s", reg64_to_str(src)); @@ -430,7 +464,7 @@ void asm_popr(Asm *self, Reg64 reg) { void asm_callr(Asm *self, Reg64 reg) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rr(reg, 0); *self->code_it++ = 0xFF; asm_rr(self, reg, 0x2); ins_end(self, "call %s", reg64_to_str(reg)); @@ -457,7 +491,7 @@ void asm_overwrite_call_rel32(Asm *self, u32 asm_index, i32 new_relative) { void asm_cmp_rm(Asm *self, Reg64 reg1, AsmPtr *reg2) { ins_start(self); - *self->code_it++ = REX_W; + *self->code_it++ = rex_rm(reg2, reg1); *self->code_it++ = 0x3B; asm_rm(self, reg2, reg1); ins_end(self, "cmp %s, %s", reg64_to_str(reg1), asm_ptr_to_string(reg2)); @@ -546,25 +580,20 @@ void asm_overwrite_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative) { } /* TODO: Remove these !*/ - /* /r */ -#define DEFINE_INS_RM(mnemonic, opcode) \ -void asm_##mnemonic##_rmb(Asm *self, Reg32 dst, Reg32 src) { \ - *self->code_it++ = opcode; \ - *self->code_it++ = 0xC0 + 8*dst + src; \ -} \ - \ -void asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \ - ins_start(self); \ - asm_##mnemonic##_rmb(self, (Reg32)dst, (Reg32)src); \ - ins_end(self, #mnemonic" %s, %s", reg32_to_str(dst), reg32_to_str(src)); \ -} \ - \ -void asm_##mnemonic##_rm64(Asm *self, Reg64 dst, Reg64 src) { \ - ins_start(self); \ - *self->code_it++ = REX_W; \ - asm_##mnemonic##_rmb(self, (Reg32)dst, (Reg32)src); \ - ins_end(self, #mnemonic" %s, %s", reg64_to_str(dst), reg64_to_str(src)); \ +#define DEFINE_INS_RM(mnemonic, opcode) \ +void asm_##mnemonic##_rm32(Asm *self, Reg32 dst, Reg32 src) { \ + ins_start(self); \ + *self->code_it++ = opcode; \ + asm_rr(self, (Reg64)src, (Reg64)dst); \ + ins_end(self, #mnemonic" %s, %s", reg32_to_str(dst), reg32_to_str(src)); \ +} \ + \ +void asm_##mnemonic##_rm64(Asm *self, Reg64 dst, Reg64 src) { \ + ins_start(self); \ + *self->code_it++ = opcode; \ + asm_rr(self, src, dst); \ + ins_end(self, #mnemonic" %s, %s", reg64_to_str(dst), reg64_to_str(src)); \ } DEFINE_INS_RM(mov, 0x8B) @@ -581,31 +610,31 @@ DEFINE_INS_RM(cmp, 0x3B) It's a number used to extend the opcode type, since the instruction only uses one register the other register can be encoded for that. */ -#define DEFINE_INS_EXT_IMM(mnemonic, extension) \ -void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i32 immediate) { \ - if(abs_i32(immediate) <= INT8_MAX) { \ - *self->code_it++ = 0x83; \ - *self->code_it++ = 0xC0 + 8*extension + reg; \ - *self->code_it++ = (u8)immediate; \ - } else { \ - *self->code_it++ = 0x81; \ - *self->code_it++ = 0xC0 + 8*extension + reg; \ - am_memcpy(self->code_it, &immediate, sizeof(immediate)); \ - self->code_it += sizeof(immediate); \ - } \ -} \ - \ -void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \ - ins_start(self); \ - asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ - ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ -}\ - \ -void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i32 immediate) { \ - ins_start(self); \ - *self->code_it++ = REX_W; \ - asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ - ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ +#define DEFINE_INS_EXT_IMM(mnemonic, extension) \ +void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i32 immediate) { \ + if(abs_i32(immediate) <= INT8_MAX) { \ + *self->code_it++ = 0x83; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + *self->code_it++ = (u8)immediate; \ + } else { \ + *self->code_it++ = 0x81; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + am_memcpy(self->code_it, &immediate, sizeof(immediate)); \ + self->code_it += sizeof(immediate); \ + } \ +} \ + \ +void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i32 immediate) { \ + ins_start(self); \ + asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ + ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ +} \ + \ +void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i32 immediate) { \ + ins_start(self); \ + *self->code_it++ = rex_rr(reg, 0); \ + asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ + ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ } DEFINE_INS_EXT_IMM(add, 0) @@ -623,28 +652,28 @@ DEFINE_INS_EXT_IMM(cmp, 7) It's a number used to extend the opcode type, since the instruction only uses one register the other register can be encoded for that. */ -#define DEFINE_INS_SHIFT_IMM8(mnemonic, extension) \ -void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i8 immediate) { \ - if(immediate == 1) { \ - *self->code_it++ = 0xC1; \ - *self->code_it++ = 0xC0 + 8*reg + extension; \ - } else { \ - *self->code_it++ = 0xD1; \ - *self->code_it++ = 0xC0 + 8*reg + extension; \ - *self->code_it++ = immediate; \ - } \ -} \ - \ -void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \ - ins_start(self); \ - ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ -} \ - \ -void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i8 immediate) { \ - ins_start(self); \ - *self->code_it++ = REX_W; \ - asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ - ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ +#define DEFINE_INS_SHIFT_IMM8(mnemonic, extension) \ +void asm_##mnemonic##_rmb_imm(Asm *self, Reg32 reg, i8 immediate) { \ + if(immediate == 1) { \ + *self->code_it++ = 0xC1; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + } else { \ + *self->code_it++ = 0xD1; \ + asm_rr(self, (Reg64)reg, (Reg64)(extension)); \ + *self->code_it++ = immediate; \ + } \ +} \ + \ +void asm_##mnemonic##_rm32_imm(Asm *self, Reg32 reg, i8 immediate) { \ + ins_start(self); \ + ins_end(self, #mnemonic" %s, 0x%x", reg32_to_str(reg), immediate); \ +} \ + \ +void asm_##mnemonic##_rm64_imm(Asm *self, Reg64 reg, i8 immediate) { \ + ins_start(self); \ + *self->code_it++ = rex_rr(reg, 0); \ + asm_##mnemonic##_rmb_imm(self, (Reg32)reg, immediate); \ + ins_end(self, #mnemonic" %s, 0x%x", reg64_to_str(reg), immediate); \ } DEFINE_INS_SHIFT_IMM8(rol, 0) diff --git a/executor/x86_64/asm.h b/executor/x86_64/asm.h index 6ac74f4..b82a63e 100644 --- a/executor/x86_64/asm.h +++ b/executor/x86_64/asm.h @@ -21,15 +21,27 @@ typedef enum { EDI } Reg32; +#define REG64_EXTENDED_REG_BIT (1 << 3) +#define REG64_REG_BITS 0x7 + typedef enum { - RAX, - RCX, - RDX, - RBX, - RSP, - RBP, - RSI, - RDI + RAX = 0, + RCX = 1, + RDX = 2, + RBX = 3, + RSP = 4, + RBP = 5, + RSI = 6, + RDI = 7, + + R8 = REG64_EXTENDED_REG_BIT | RAX, + R9 = REG64_EXTENDED_REG_BIT | RCX, + R10 = REG64_EXTENDED_REG_BIT | RDX, + R11 = REG64_EXTENDED_REG_BIT | RBX, + R12 = REG64_EXTENDED_REG_BIT | RSP, + R13 = REG64_EXTENDED_REG_BIT | RBP, + R14 = REG64_EXTENDED_REG_BIT | RSI, + R15 = REG64_EXTENDED_REG_BIT | RDI } Reg64; typedef struct { 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; } |