aboutsummaryrefslogtreecommitdiff
path: root/executor/x86_64/asm.c
diff options
context:
space:
mode:
Diffstat (limited to 'executor/x86_64/asm.c')
-rw-r--r--executor/x86_64/asm.c86
1 files changed, 66 insertions, 20 deletions
diff --git a/executor/x86_64/asm.c b/executor/x86_64/asm.c
index 73ae568..f032538 100644
--- a/executor/x86_64/asm.c
+++ b/executor/x86_64/asm.c
@@ -35,6 +35,10 @@ static void ins_start(Asm *self) {
asm_debug_str_buffer_index = 0;
}
+static int max(int a, int b) {
+ return a >= b ? a : b;
+}
+
static void ins_end(Asm *self, const char *fmt, ...) {
usize ins_end_offset;
usize i;
@@ -46,7 +50,7 @@ static void ins_end(Asm *self, const char *fmt, ...) {
fprintf(stderr, "%02x ", ((u8*)self->code)[i]);
}
/* Same padding for all instructions, no matter how long they are */
- for(i = 0; i < 35 - (ins_end_offset - ins_start_offset)*3; ++i) {
+ for(i = 0; i < (usize)max(0, 35 - (ins_end_offset - ins_start_offset)*3); ++i) {
putc(' ', stderr);
}
vfprintf(stderr, fmt, args);
@@ -160,9 +164,9 @@ void asm_ptr_init_index_disp(AsmPtr *self, Reg64 base, Reg64 index, i32 disp) {
}
int asm_init(Asm *self) {
- self->size = am_pagesize();
- amal_log_debug("asm: page size: %u", self->size);
- self->code = mmap(NULL, self->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ self->allocated_size = am_pagesize();
+ amal_log_debug("asm: page size: %u", self->allocated_size);
+ self->code = mmap(NULL, self->allocated_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(self->code == MAP_FAILED)
return -errno;
self->code_it = self->code;
@@ -171,12 +175,17 @@ int asm_init(Asm *self) {
void asm_deinit(Asm *self) {
if(self->code)
- munmap(self->code, self->size);
+ munmap(self->code, self->allocated_size);
self->code = NULL;
self->code_it = NULL;
- self->size = 0;
+ self->allocated_size = 0;
+}
+
+usize asm_get_size(Asm *self) {
+ return self->code_it - (u8*)self->code;
}
+#if 0
static void asm_print_code_hex(Asm *self) {
u8 *ptr;
int off;
@@ -196,13 +205,14 @@ static void asm_print_code_hex(Asm *self) {
if(off != 0)
putc('\n', stdout);
}
+#endif
int asm_execute(Asm *self) {
void (*func)();
- if(mprotect(self->code, self->size, PROT_READ | PROT_EXEC) != 0)
+ if(mprotect(self->code, self->allocated_size, PROT_READ | PROT_EXEC) != 0)
return -errno;
- asm_print_code_hex(self);
+ /*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;
@@ -214,17 +224,17 @@ int asm_execute(Asm *self) {
static CHECK_RESULT int asm_ensure_capacity(Asm *self, usize size) {
usize current_offset;
current_offset = (u8*)self->code_it - (u8*)self->code;
- if(current_offset + size > self->size) {
+ if(current_offset + size > self->allocated_size) {
void *new_mem;
usize new_size;
- new_size = self->size + am_pagesize();
+ 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)
return -errno;
- am_memcpy(new_mem, self->code, self->size);
+ am_memcpy(new_mem, self->code, self->allocated_size);
self->code = new_mem;
- self->size = new_size;
+ self->allocated_size = new_size;
self->code_it = (u8*)self->code + current_offset;
}
return 0;
@@ -232,7 +242,7 @@ static CHECK_RESULT int asm_ensure_capacity(Asm *self, usize size) {
#ifdef DEBUG
static isize asm_get_capacity_left(Asm *self) {
- return (isize)self->size - (isize)((u8*)self->code_it - (u8*)self->code);
+ return (isize)self->allocated_size - (isize)((u8*)self->code_it - (u8*)self->code);
}
#endif
@@ -346,21 +356,20 @@ int asm_mov_rm(Asm *self, Reg64 dst, AsmPtr *src) {
return 0;
}
+/* Note: This shows as instruction movabs in intel assembly format */
int asm_mov_ri(Asm *self, Reg64 dst, i64 immediate) {
ins_start(self);
- /* 10 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 10));
*self->code_it++ = REX_W;
*self->code_it++ = 0xB8 + dst;
am_memcpy(self->code_it, &immediate, sizeof(immediate));
self->code_it += sizeof(immediate);
- ins_end(self, "mov %s, %ld", reg64_to_str(dst), immediate);
+ ins_end(self, "mov %s, 0x%x", reg64_to_str(dst), immediate);
return 0;
}
int asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) {
ins_start(self);
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = REX_W;
*self->code_it++ = 0x89;
@@ -371,7 +380,6 @@ int asm_mov_rr(Asm *self, Reg64 dst, Reg64 src) {
int asm_add_rr(Asm *self, Reg64 dst, Reg64 src) {
ins_start(self);
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = REX_W;
*self->code_it++ = 0x01;
@@ -382,7 +390,6 @@ int asm_add_rr(Asm *self, Reg64 dst, Reg64 src) {
int asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) {
ins_start(self);
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = REX_W;
*self->code_it++ = 0x29;
@@ -393,7 +400,6 @@ int asm_sub_rr(Asm *self, Reg64 dst, Reg64 src) {
int asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) {
ins_start(self);
- /* 3 bytes is the maximum size of the instruction. We don't how how large it will be so we prepare for the largest size */
return_if_error(asm_ensure_capacity(self, 4));
*self->code_it++ = REX_W;
*self->code_it++ = 0x0F;
@@ -403,6 +409,25 @@ int asm_imul_rr(Asm *self, Reg64 dst, Reg64 src) {
return 0;
}
+int asm_cqo(Asm *self) {
+ ins_start(self);
+ return_if_error(asm_ensure_capacity(self, 2));
+ *self->code_it++ = REX_W;
+ *self->code_it++ = 0x99;
+ ins_end(self, "cqo");
+ return 0;
+}
+
+int asm_idiv_rr(Asm *self, Reg64 src) {
+ ins_start(self);
+ return_if_error(asm_ensure_capacity(self, 4));
+ *self->code_it++ = REX_W;
+ *self->code_it++ = 0xF7;
+ asm_rr(self, src, 0x7);
+ ins_end(self, "idiv %s", reg64_to_str(src));
+ return 0;
+}
+
int asm_pushr(Asm *self, Reg64 reg) {
ins_start(self);
return_if_error(asm_ensure_capacity(self, 1));
@@ -419,6 +444,26 @@ int asm_popr(Asm *self, Reg64 reg) {
return 0;
}
+/*
+ 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
+*/
+int asm_call_rel32(Asm *self, i32 relative) {
+ ins_start(self);
+ relative -= 5; /* In x86, the relative position starts from the next instruction */
+ return_if_error(asm_ensure_capacity(self, 5));
+ *self->code_it++ = 0xE8;
+ am_memcpy(self->code_it, &relative, sizeof(relative));
+ self->code_it += sizeof(relative);
+ ins_end(self, "call 0x%x", relative);
+ return 0;
+}
+
+void asm_override_call_rel32(Asm *self, u32 asm_index, i32 new_relative) {
+ 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));
+}
+
/* TODO: Remove these !*/
/* /r */
@@ -559,11 +604,12 @@ int asm_ret(Asm *self, u16 bytes) {
if(bytes == 0) {
return_if_error(asm_ensure_capacity(self, 1));
*self->code_it++ = 0xC3;
+ ins_end(self, "ret");
} else {
return_if_error(asm_ensure_capacity(self, 3));
*self->code_it++ = 0xC2;
am_memcpy(self->code_it, &bytes, sizeof(bytes));
+ ins_end(self, "ret 0x%x", bytes);
}
- ins_end(self, "ret 0x%x", bytes);
return 0;
}