aboutsummaryrefslogtreecommitdiff
path: root/executor/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'executor/x86_64')
-rw-r--r--executor/x86_64/asm.c34
-rw-r--r--executor/x86_64/asm.h8
-rw-r--r--executor/x86_64/executor.c77
3 files changed, 45 insertions, 74 deletions
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c
index c2b00ef..e29130e 100644
--- a/executor/x86_64/asm.c
+++ b/executor/x86_64/asm.c
@@ -218,24 +218,22 @@ int asm_execute(Asm *self, u32 offset) {
/*asm_print_code_hex(self);*/
/* TODO: Verify if this is valid on all platforms. According to ISO C standard it isn't? */
- *(void**)(&func) = self->code + offset;
+ *(void**)(&func) = (u8*)self->code + offset;
func();
return 0;
}
/* TODO: See how this can be optimized */
int asm_ensure_capacity(Asm *self, usize size) {
- usize current_offset;
- current_offset = (u8*)self->code_it - (u8*)self->code;
+ usize current_offset = (u8*)self->code_it - (u8*)self->code;
if(current_offset + size > self->allocated_size) {
- void *new_mem;
- usize new_size;
- new_size = self->allocated_size + am_pagesize();
- new_mem = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if(self->code == MAP_FAILED)
+ usize new_size = self->allocated_size + am_pagesize();
+ void *new_mem = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if(new_mem == MAP_FAILED)
return -errno;
am_memcpy(new_mem, self->code, self->allocated_size);
+ munmap(self->code, self->allocated_size);
self->code = new_mem;
self->allocated_size = new_size;
self->code_it = (u8*)self->code + current_offset;
@@ -435,7 +433,7 @@ void asm_callr(Asm *self, Reg64 reg) {
/*
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_override_call_rel32. TODO: Update the ins_end debug print to take that into account somehow
+ is later changed with @asm_overwrite_call_rel32. TODO: Update the ins_end debug print to take that into account somehow
*/
void asm_call_rel32(Asm *self, i32 relative) {
ins_start(self);
@@ -446,8 +444,8 @@ void asm_call_rel32(Asm *self, i32 relative) {
ins_end(self, "call 0x%x", relative);
}
-void asm_override_call_rel32(Asm *self, u32 asm_index, i32 new_relative) {
- assert(*(u8*)(self->code + asm_index) == 0xE8);
+void asm_overwrite_call_rel32(Asm *self, u32 asm_index, i32 new_relative) {
+ assert(*((u8*)self->code + asm_index) == 0xE8);
new_relative -= 5; /* In x86, the relative position starts from the next instruction */
am_memcpy((u8*)self->code + asm_index + 1, &new_relative, sizeof(new_relative));
}
@@ -480,7 +478,7 @@ void asm_sete_r(Asm *self, Reg64 dst) {
/*
Note: This is sometimes called with @relative INT32_MAX-(2 or 6) (will print jz 0x7ffffff9), in which case it's most likely a dummy
- jump until the relative position is later changed with @asm_override_jcc_rel32.
+ jump until the relative position is later changed with @asm_overwrite_jcc_rel32.
TODO: Update the ins_end debug print to take that into account somehow
*/
void asm_jz(Asm *self, i32 relative) {
@@ -503,17 +501,17 @@ void asm_jz(Asm *self, i32 relative) {
ins_end(self, "jz 0x%x", relative);
}
-void asm_override_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative) {
+void asm_overwrite_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative) {
/* +2 because rel32 variant of the jump instruction opcode is 2 bytes */
- assert(*(u8*)(self->code + asm_index) == 0x0F);
- assert(*(u8*)(self->code + asm_index + 1) == 0x84);
+ assert(*((u8*)self->code + asm_index) == 0x0F);
+ assert(*((u8*)self->code + asm_index + 1) == 0x84);
new_relative -= 6; /* In x86, the relative position starts from the next instruction */
am_memcpy((u8*)self->code + asm_index + 2, &new_relative, sizeof(new_relative));
}
/*
Note: This is sometimes called with @relative INT32_MAX-(2 or 5) (will print jmp 0x7ffffffa), in which case it's most likely a dummy
- jump until the relative position is later changed with @asm_override_jmp_rel32.
+ jump until the relative position is later changed with @asm_overwrite_jmp_rel32.
TODO: Update the ins_end debug print to take that into account somehow
*/
void asm_jmp(Asm *self, i32 relative) {
@@ -535,9 +533,9 @@ void asm_jmp(Asm *self, i32 relative) {
ins_end(self, "jmp 0x%x", relative);
}
-void asm_override_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative) {
+void asm_overwrite_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative) {
/* +1 to skip instruction opcode */
- assert(*(u8*)(self->code + asm_index) == 0xE9);
+ assert(*((u8*)self->code + asm_index) == 0xE9);
new_relative -= 5; /* In x86, the relative position starts from the next instruction */
am_memcpy((u8*)self->code + asm_index + 1, &new_relative, sizeof(new_relative));
}
diff --git a/executor/x86_64/asm.h b/executor/x86_64/asm.h
index a3f1b5a..6ac74f4 100644
--- a/executor/x86_64/asm.h
+++ b/executor/x86_64/asm.h
@@ -88,7 +88,7 @@ void asm_callr(Asm *self, Reg64 reg);
by this asm library itself.
*/
void asm_call_rel32(Asm *self, i32 relative);
-void asm_override_call_rel32(Asm *self, u32 asm_index, i32 new_relative);
+void asm_overwrite_call_rel32(Asm *self, u32 asm_index, i32 new_relative);
void asm_cmp_rm(Asm *self, Reg64 reg1, AsmPtr *reg2);
/*
@@ -104,15 +104,15 @@ void asm_sete_r(Asm *self, Reg64 dst);
by this asm library itself.
*/
void asm_jz(Asm *self, i32 relative);
-/* Override conditional jump target */
-void asm_override_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative);
+/* Overwrite conditional jump target */
+void asm_overwrite_jcc_rel32(Asm *self, u32 asm_index, i32 new_relative);
/*
In x86 assembly, the @relative position starts from the next instruction.
This offset shouldn't be calculated by the caller and is instead managed
by this asm library itself.
*/
void asm_jmp(Asm *self, i32 relative);
-void asm_override_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative);
+void asm_overwrite_jmp_rel32(Asm *self, u32 asm_index, i32 new_relative);
diff --git a/executor/x86_64/executor.c b/executor/x86_64/executor.c
index 9083e14..c442da8 100644
--- a/executor/x86_64/executor.c
+++ b/executor/x86_64/executor.c
@@ -1,6 +1,7 @@
#include "../executor.h"
#include "../../include/std/alloc.h"
#include "../../include/std/buffer.h"
+#include "../../include/std/log.h"
#include "asm.h"
#include <assert.h>
@@ -19,29 +20,23 @@
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 ASM_ENSURE_CAPACITY return_if_error(asm_ensure_capacity(&impl->asm, 256));
+
#define IMPL_START \
amal_executor_impl *impl = (amal_executor_impl*)self; \
- return_if_error(asm_ensure_capacity(&impl->asm, 256));
+ ASM_ENSURE_CAPACITY
/*
@reg will be a positive value when accessing local variables, in which case the first
@@ -64,10 +59,7 @@ int amal_executor_init(amal_executor **self) {
impl = (amal_executor_impl**)self;
*impl = NULL;
return_if_error(am_malloc(sizeof(amal_executor_impl), (void**)impl));
- (*impl)->function_indices = NULL;
- (*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);
@@ -76,8 +68,6 @@ int amal_executor_init(amal_executor **self) {
void amal_executor_deinit(amal_executor *self) {
amal_executor_impl *impl = (amal_executor_impl*)self;
buffer_deinit(&impl->jump_defer);
- buffer_deinit(&impl->call_defer);
- am_free(impl->function_indices);
asm_deinit(&impl->asm);
am_free(impl);
}
@@ -93,26 +83,13 @@ u32 amal_exec_get_code_offset(amal_executor *self) {
}
int amal_executor_instructions_start(amal_executor *self, u16 num_functions) {
- amal_executor_impl *impl = (amal_executor_impl*)self;
- return_if_error(am_realloc(impl->function_indices, num_functions * sizeof(usize), (void**)&impl->function_indices));
- impl->num_functions = num_functions;
+ (void)self;
+ (void)num_functions;
return 0;
}
int amal_executor_instructions_end(amal_executor *self) {
amal_executor_impl *impl = (amal_executor_impl*)self;
- 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) {
- 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;
}
@@ -299,25 +276,16 @@ int amal_exec_pushd(amal_executor *self, BufferView data) {
return 0;
}
-int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args, i8 dst_reg) {
- IMPL_START
+int amal_exec_call(amal_executor *self, u32 code_offset, u8 num_args, 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);
- if(func_index < impl->func_counter) {
- 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_offset;
- call_defer.func_index = func_index;
- return_if_error(buffer_append(&impl->call_defer, &call_defer, sizeof(call_defer)));
- asm_call_rel32(&impl->asm, 0);
- }
+ ASM_ENSURE_CAPACITY
+
+ assert(code_offset < asm_offset);
+ asm_call_rel32(&impl->asm, (isize)code_offset - asm_offset);
/* Handle function result and cleanup */
{
@@ -331,6 +299,11 @@ int amal_exec_call(amal_executor *self, u16 func_index, u8 num_args, i8 dst_reg)
return 0;
}
+void amal_exec_call_overwrite(amal_executor *self, u32 call_code_offset, i32 new_target_rel32) {
+ amal_executor_impl *impl = (amal_executor_impl*)self;
+ asm_overwrite_call_rel32(&impl->asm, call_code_offset, new_target_rel32);
+}
+
const Reg64 SYS_V_PARAM_REGS[] = { RDI, RSI, RDX, RCX };
/*
@@ -379,9 +352,9 @@ 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) {
+ AsmPtr dst, src1, src2;
IMPL_START
- 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));
@@ -424,8 +397,9 @@ int amal_exec_jz(amal_executor *self, i8 reg, u16 target_label) {
}
int amal_exec_jmp(amal_executor *self, u16 target_label) {
- IMPL_START
+ amal_executor_impl *impl = (amal_executor_impl*)self;
u32 asm_offset = asm_get_size(&impl->asm);
+ ASM_ENSURE_CAPACITY
if(target_label < impl->label_counter) {
asm_jmp(&impl->asm, (i32)impl->label_asm_index[target_label] - (i32)asm_offset);
return 0;
@@ -466,7 +440,6 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) {
64-bit Linux,BSD,Mac: RBX, RBP, R12-R15
*/
IMPL_START
- impl->function_indices[impl->func_counter++] = asm_get_size(&impl->asm);
asm_pushr(&impl->asm, RBX);
asm_pushr(&impl->asm, RBP);
asm_mov_rr(&impl->asm, RBP, RSP);
@@ -475,10 +448,10 @@ int amal_exec_func_start(amal_executor *self, u16 num_regs) {
}
int amal_exec_func_end(amal_executor *self) {
- IMPL_START
-
+ amal_executor_impl *impl = (amal_executor_impl*)self;
JumpDefer *jump_defer = buffer_begin(&impl->jump_defer);
JumpDefer *jump_defer_end = buffer_end(&impl->jump_defer);
+ ASM_ENSURE_CAPACITY
for(; jump_defer != jump_defer_end; ++jump_defer) {
i32 jump_offset;
if(jump_defer->target_label >= impl->label_counter) {
@@ -487,9 +460,9 @@ int amal_exec_func_end(amal_executor *self) {
}
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);
+ asm_overwrite_jcc_rel32(&impl->asm, jump_defer->asm_index, jump_offset);
else
- asm_override_jmp_rel32(&impl->asm, jump_defer->asm_index, jump_offset);
+ asm_overwrite_jmp_rel32(&impl->asm, jump_defer->asm_index, jump_offset);
}
buffer_clear(&impl->jump_defer);
impl->label_counter = 0;
@@ -502,7 +475,7 @@ int amal_exec_func_end(amal_executor *self) {
}
int amal_exec_label(amal_executor *self) {
- IMPL_START
+ amal_executor_impl *impl = (amal_executor_impl*)self;
assert(impl->label_counter < MAX_LABELS);
impl->label_asm_index[impl->label_counter++] = asm_get_size(&impl->asm);
return 0;