aboutsummaryrefslogtreecommitdiff
path: root/executor
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-09-17 01:28:55 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commitb095aedd386e076d1f5a56b7384b836e653387d1 (patch)
treea9dd7d7cbcfba19005ce8aa9486a70d31091d5c3 /executor
parent2928e5f74983f5dd33bc65f192298af87996a037 (diff)
Add support for r8-r15 registers, pass args to registers directly (sys-v)
Diffstat (limited to 'executor')
-rw-r--r--executor/executor.h5
-rw-r--r--executor/x86_64/asm.c203
-rw-r--r--executor/x86_64/asm.h28
-rw-r--r--executor/x86_64/executor.c65
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, &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;
}