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.c151
1 files changed, 115 insertions, 36 deletions
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c
index 335790a..d35dbdc 100644
--- a/executor/x86_64/executor.c
+++ b/executor/x86_64/executor.c
@@ -11,22 +11,35 @@
TODO: Operations with memory registers could access outside the stack. Should this be checked?
*/
+/*
+ TODO: Allow this to dynamically change up to 1<<16, to match jump instruction.
+ This is a sane limit for now
+*/
+#define MAX_LABELS 128
+
typedef struct {
u32 asm_index;
u16 func_index;
} CallDefer;
typedef struct {
+ u32 asm_index;
+ u16 target_label;
+ bool condition;
+} JumpDefer;
+
+typedef struct {
Asm asm;
usize *function_indices;
u16 num_functions;
u16 func_counter;
Buffer/*CallDefer*/ call_defer;
+ Buffer/*JumpDefer*/ jump_defer;
+ u32 label_asm_index[MAX_LABELS];
+ int label_counter;
} amal_executor_impl;
-#define IMPL \
- amal_executor_impl *impl; \
- impl = (amal_executor_impl*)self;
+#define IMPL amal_executor_impl *impl = (amal_executor_impl*)self;
/*
@reg will be a positive value when accessing local variables, in which case the first
@@ -53,11 +66,14 @@ int amal_executor_init(amal_executor **self) {
(*impl)->num_functions = 0;
(*impl)->func_counter = 0;
ignore_result_int(buffer_init(&(*impl)->call_defer, NULL));
+ ignore_result_int(buffer_init(&(*impl)->jump_defer, NULL));
+ (*impl)->label_counter = 0;
return asm_init(&(*impl)->asm);
}
void amal_executor_deinit(amal_executor *self) {
IMPL
+ buffer_deinit(&impl->jump_defer);
buffer_deinit(&impl->call_defer);
am_free(impl->function_indices);
asm_deinit(&impl->asm);
@@ -75,26 +91,28 @@ u32 amal_exec_get_code_offset(amal_executor *self) {
}
int amal_executor_instructions_start(amal_executor *self, u16 num_functions) {
- void *new_data;
IMPL
- return_if_error(am_realloc(impl->function_indices, num_functions * sizeof(*impl->function_indices), &new_data));
- impl->function_indices = new_data;
+ return_if_error(am_realloc(impl->function_indices, num_functions * sizeof(usize), (void**)&impl->function_indices));
impl->num_functions = num_functions;
- impl->func_counter = 0;
- buffer_clear(&impl->call_defer);
return 0;
}
int amal_executor_instructions_end(amal_executor *self) {
- CallDefer *call_defer, *call_defer_end;
IMPL
- call_defer = buffer_begin(&impl->call_defer);
- call_defer_end = buffer_end(&impl->call_defer);
+ CallDefer *call_defer = buffer_begin(&impl->call_defer);
+ CallDefer *call_defer_end = buffer_end(&impl->call_defer);
for(; call_defer != call_defer_end; ++call_defer) {
- const isize func_offset = (isize)impl->function_indices[call_defer->func_index] - (isize)call_defer->asm_index;
+ i32 func_offset;
+ if(call_defer->func_index >= impl->num_functions) {
+ amal_log_error("Program attempted to call a function that doesn't exist (index %u, while there are only %u functions)", call_defer->func_index, impl->num_functions);
+ return -1;
+ }
+ func_offset = (isize)impl->function_indices[call_defer->func_index] - (isize)call_defer->asm_index;
asm_override_call_rel32(&impl->asm, call_defer->asm_index, func_offset);
}
+ buffer_clear(&impl->call_defer);
+ impl->func_counter = 0;
return 0;
}
@@ -272,25 +290,26 @@ int amal_exec_pushd(amal_executor *self, BufferView data) {
}
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? */
/* TODO: This assumes all arguments are isize */
- asm_size = asm_get_size(&impl->asm);
+ /* Do the function call */
+ isize asm_offset = asm_get_size(&impl->asm);
if(func_index < impl->func_counter) {
- return_if_error(asm_call_rel32(&impl->asm, (isize)impl->function_indices[func_index] - asm_size));
+ return_if_error(asm_call_rel32(&impl->asm, (isize)impl->function_indices[func_index] - asm_offset));
} else {
/*
The location of the function has not been defined yet. Use call instruction with dummy data and change
the location once the location to the function is known
*/
CallDefer call_defer;
- call_defer.asm_index = asm_size;
+ call_defer.asm_index = asm_offset;
call_defer.func_index = func_index;
return_if_error(buffer_append(&impl->call_defer, &call_defer, sizeof(call_defer)));
return_if_error(asm_call_rel32(&impl->asm, 0));
}
+ /* Handle function result and cleanup */
{
AsmPtr dst;
asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg));
@@ -350,30 +369,65 @@ int amal_exec_callr(i8 dst_reg, BufferView data) {
*/
int amal_exec_cmp(amal_executor *self, i8 dst_reg, i8 src_reg1, i8 src_reg2) {
- (void)self;
- (void)dst_reg;
- (void)src_reg1;
- (void)src_reg2;
- /* TODO: Implement! */
- assert(bool_false && "TODO: Implement!");
- return 0;
+ IMPL
+
+ AsmPtr dst, src1, src2;
+ asm_ptr_init_disp(&dst, RBP, get_register_stack_offset(dst_reg));
+ asm_ptr_init_disp(&src1, RBP, get_register_stack_offset(src_reg1));
+ asm_ptr_init_disp(&src2, RBP, get_register_stack_offset(src_reg2));
+
+ return_if_error(asm_mov_rm(&impl->asm, RCX, &dst));
+ return_if_error(asm_xor_rm64(&impl->asm, RCX, RCX));
+
+ return_if_error(asm_mov_rm(&impl->asm, RAX, &src1));
+ return_if_error(asm_cmp_rm(&impl->asm, RAX, &src2));
+ return_if_error(asm_sete_r(&impl->asm, RCX));
+ return asm_mov_mr(&impl->asm, &dst, RCX);
}
-int amal_exec_jz(amal_executor *self, i8 dst_reg, i16 offset) {
- (void)self;
- (void)dst_reg;
- (void)offset;
- /* TODO: Implement! */
- assert(bool_false && "TODO: Implement!");
- return 0;
+int amal_exec_jz(amal_executor *self, i8 reg, u16 target_label) {
+ AsmPtr ptr;
+ u32 asm_offset;
+ IMPL
+
+ asm_ptr_init_disp(&ptr, RBP, get_register_stack_offset(reg));
+ return_if_error(asm_mov_rm(&impl->asm, RAX, &ptr));
+ return_if_error(asm_cmp_rm64_imm(&impl->asm, RAX, 0));
+
+ asm_offset = asm_get_size(&impl->asm);
+ if(target_label < impl->label_counter) {
+ return asm_jz(&impl->asm, (i32)impl->label_asm_index[target_label] - (i32)asm_offset);
+ } else {
+ JumpDefer jump_defer;
+ jump_defer.asm_index = asm_offset;
+ jump_defer.target_label = target_label;
+ jump_defer.condition = bool_true;
+ /*
+ Insert dummy target, but it has to be above INT16_MAX, so the target can be replaced
+ no matter how large the jump will be
+ */
+ return_if_error(asm_jz(&impl->asm, INT32_MAX));
+ return buffer_append(&impl->jump_defer, &jump_defer, sizeof(jump_defer));
+ }
}
-int amal_exec_jmp(amal_executor *self, i16 offset) {
- (void)self;
- (void)offset;
- /* TODO: Implement! */
- assert(bool_false && "TODO: Implement!");
- return 0;
+int amal_exec_jmp(amal_executor *self, u16 target_label) {
+ IMPL
+ u32 asm_offset = asm_get_size(&impl->asm);
+ if(target_label < impl->label_counter) {
+ return asm_jmp(&impl->asm, (i32)impl->label_asm_index[target_label] - (i32)asm_offset);
+ } else {
+ JumpDefer jump_defer;
+ jump_defer.asm_index = asm_offset;
+ jump_defer.target_label = target_label;
+ jump_defer.condition = bool_false;
+ /*
+ Insert dummy target, but it has to be above INT16_MAX, so the target can be replaced
+ no matter how large the jump will be
+ */
+ return_if_error(asm_jmp(&impl->asm, INT32_MAX));
+ return buffer_append(&impl->jump_defer, &jump_defer, sizeof(jump_defer));
+ }
}
int amal_exec_ret(amal_executor *self, i8 reg) {
@@ -408,8 +462,33 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) {
int amal_exec_func_end(amal_executor *self) {
IMPL
+
+ JumpDefer *jump_defer = buffer_begin(&impl->jump_defer);
+ JumpDefer *jump_defer_end = buffer_end(&impl->jump_defer);
+ for(; jump_defer != jump_defer_end; ++jump_defer) {
+ i32 jump_offset;
+ if(jump_defer->target_label >= impl->label_counter) {
+ amal_log_error("Program attempted to jump to a label that doesn't exist (label %u, while there are only %u labels)", jump_defer->target_label, impl->label_counter);
+ return -1;
+ }
+ jump_offset = (isize)impl->label_asm_index[jump_defer->target_label] - (isize)jump_defer->asm_index;
+ if(jump_defer->condition)
+ asm_override_jcc_rel32(&impl->asm, jump_defer->asm_index, jump_offset);
+ else
+ asm_override_jmp_rel32(&impl->asm, jump_defer->asm_index, jump_offset);
+ }
+ buffer_clear(&impl->jump_defer);
+ impl->label_counter = 0;
+
return_if_error(asm_mov_rr(&impl->asm, RSP, RBP));
return_if_error(asm_popr(&impl->asm, RBP));
return_if_error(asm_popr(&impl->asm, RBX));
return asm_ret(&impl->asm, 0);
}
+
+int amal_exec_label(amal_executor *self) {
+ IMPL
+ assert(impl->label_counter < MAX_LABELS);
+ impl->label_asm_index[impl->label_counter++] = asm_get_size(&impl->asm);
+ return 0;
+}