summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-07-25 10:53:07 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-07-25 10:53:07 +0200
commitfea7c754e443e29b1185fc3cfe50a3c778ccb82b (patch)
treebf180c9d523e16bd6b9f108b0283f3093c2c64d0
parente9934a81f6c69596c0f183abc411804a9d450208 (diff)
downloadbxgen-fea7c754e443e29b1185fc3cfe50a3c778ccb82b.zip
Codegen: x86_64 exit syscall
-rwxr-xr-xbxgen.c134
1 files changed, 108 insertions, 26 deletions
diff --git a/bxgen.c b/bxgen.c
index 92285b0..6951657 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -303,7 +303,16 @@ typedef struct {
union {
u8 lit_bytes[MAX_LITERAL_SIZE]; // byte array literal
// TODO use string table
- i64 lit_int; // integer literal
+ i8 lit_i8;
+ i16 lit_i16;
+ i32 lit_i32;
+ i64 lit_i64;
+ u8 lit_u8;
+ u16 lit_u16;
+ u32 lit_u32;
+ u64 lit_u64;
+ f32 lit_f32;
+ f64 lit_f64;
Ret ret;
Call call;
};
@@ -708,7 +717,7 @@ void node_destroy(Pool *pool, i64 node) {
i64 node_data_i64(Pool *pool, i64 value) {
return node_init(pool, (Node) {
.op = DATA_I64,
- .lit_int = value,
+ .lit_i64 = value,
});
}
@@ -1466,6 +1475,10 @@ enum {
R_X86_64_RELATIVE64,
R_X86_64_GOTPCRELX = 41,
R_X86_64_REX_GOTPCRELX,
+
+ // Codegen context
+
+ EMIT_ENTRY_PROC = 1,
};
c8 *SEC_TYPE_NAMES[] = {
@@ -1608,28 +1621,105 @@ typedef struct {
} Relx_Entry;
// ================================================================
+//
+// Codegen
+//
-i64 codegen_in_memory(Pool *pool, i64 unit, u16 arch) {
- BX_CHECK(arch == ARCH_X86_64, "Target not supported",);
+i64 x86_64_emit_node(Pool *pool, i64 offset, i64 node, u32 context) {
+ BX_CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0);
+ BX_CHECK(node != UNDEFINED && pool->entities[node].is_enabled, "No node", 0);
+ BX_CHECK(pool->entities[node].type == ENTITY_NODE, "Invalid entity", 0);
- u8 code[32] = {
- 0xb8, 0x3c, 0x00, 0x00, 0x00, // mov eax, 60
- 0xbf, 0x2a, 0x00, 0x00, 0x00, // mov edi, 42
- 0x0f, 0x05, // syscall
- };
+ Node *n = &pool->entities[node].node;
+
+ u8 *begin = pool->code_buffer + offset;
+ u8 *end = pool->code_buffer + pool->max_code_size;
+
+ switch (n->op) {
+ case DATA_I64: {
+ // Do nothing
+ } break;
+
+ case CTRL_CALL: {
+ BX_FAIL("Not implemented", 0);
+ } break;
+
+ case CTRL_RET: {
+ // TEMP We just emit an exit syscall.
+
+ BX_CHECK((context & EMIT_ENTRY_PROC) != 0, "Not implemented", 0);
+ BX_CHECK(n->ret.num_vals == 1, "Not implemented", 0);
+ BX_CHECK(n->ret.vals[0].num == 1, "Not implemented", 0);
+
+ i64 n_val = n->ret.vals[0].node;
+ BX_CHECK(n_val != UNDEFINED, "Internal", 0);
+ BX_CHECK(pool->entities[n_val].is_enabled, "Internal", 0);
+ BX_CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal", 0);
+
+ Node *val = &pool->entities[n_val].node;
+ BX_CHECK(val->op == DATA_I64, "Not implemented", 0);
+
+ write_u8 (LE, 0xb8, begin, end); // mov eax
+ write_u32(LE, 60, begin + 1, end); // 60
+
+ write_u8 (LE, 0xbf, begin + 5, end); // mov edi
+ write_u32(LE, val->lit_u32, begin + 6, end); // <- literal
+
+ write_u8 (LE, 0x0f, begin + 10, end); // syscall
+ write_u8 (LE, 0x05, begin + 11, end);
+
+ offset += 12;
+ } break;
+
+ default:
+ BX_FAIL("Unknown operation", 0);
+ }
- i64 code_size = bx_align(sizeof code, X86_64_ALIGNMENT);
+ return offset;
+}
+
+i64 emit_proc(Pool *pool, i64 offset, i64 proc, u16 arch, u32 context) {
+ BX_CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0);
+ BX_CHECK(proc != UNDEFINED && pool->entities[proc].is_enabled, "No proc", 0);
+ BX_CHECK(pool->entities[proc].type == ENTITY_PROC, "Invalid entity", 0);
+ BX_CHECK(arch == ARCH_X86_64, "Target not supported", 0);
- BX_CHECK(code_size <= pool->max_code_size, "Out of memory", 0);
+ Proc *p = &pool->entities[proc].proc;
- bx_mem_cpy(pool->code_buffer, code, sizeof code);
+ // TODO Sort nodes in the sequential execution order.
+ //
+ // NOTE
+ // Now we assume that nodes are already sorted.
- pool->entry_point = 0;
+ for (i64 i = 0; i < p->num_nodes; ++i)
+ offset = x86_64_emit_node(pool, offset, p->nodes[i], context);
- return code_size;
+ return offset;
+}
+
+i64 emit_unit(Pool *pool, i64 offset, i64 unit, u16 arch) {
+ BX_CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0);
+ BX_CHECK(unit != UNDEFINED && pool->entities[unit].is_enabled, "No unit", 0);
+ BX_CHECK(pool->entities[unit].type == ENTITY_UNIT, "Invalid entity", 0);
+
+ for (i64 i = 0; i < pool->entities[unit].unit.num_procs; ++i) {
+ u32 context = 0;
+
+ if (i == pool->entities[unit].unit.entry_point_index) {
+ pool->entry_point = offset;
+ context |= EMIT_ENTRY_PROC;
+ }
+
+ offset = emit_proc(pool, offset, pool->entities[unit].unit.procs[i], arch, context);
+ }
+
+ return offset;
}
// ================================================================
+//
+// Linking
+//
i64 ar_find_symbol_offset_by_name(
u8 *ar_symbol_table,
@@ -2092,19 +2182,15 @@ void elf_dump(u32 log_level, Buffer_Context b) {
i64 unit_write_in_memory(Pool *pool, i64 unit, u16 format, u16 arch) {
BX_CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments",);
- BX_CHECK(pool->entities[unit].is_enabled, "Unit does not exist",);
+ BX_CHECK(unit != UNDEFINED && pool->entities[unit].is_enabled, "No unit",);
+ BX_CHECK(pool->entities[unit].type == ENTITY_UNIT, "Invalid entity", 0);
BX_CHECK(pool->entities[unit].unit.entry_point_index != UNDEFINED, "No entry point",);
- BX_CHECK(format == FORMAT_ELF, "Target not supported",);
- BX_CHECK(arch == ARCH_X86_64, "Target not supported",);
+ BX_CHECK(format == FORMAT_ELF && arch == ARCH_X86_64, "Target not supported",);
BX_CHECK(pool->obj_file_buffer != NULL, "No object file buffer",);
BX_CHECK(pool->dependencies_buffer != NULL, "No dependencies buffer",);
BX_CHECK(pool->obj_file_offsets != NULL, "No object file offsets buffer",);
- // ==============================================================
- //
- // Codegen
-
- i64 code_size = codegen_in_memory(pool, unit, arch);
+ i64 code_size = emit_unit(pool, 0, unit, arch);
u16 num_program_headers = 4;
i64 program_offset = bx_align(ELF_HEADER_SIZE + ELF_PROGRAM_HEADER_SIZE * num_program_headers, X86_64_ALIGNMENT);
@@ -3071,10 +3157,6 @@ int main(int argc, char **argv) {
// Set the `main` as the entry point of the compilation unit.
u_entry_point(u, main);
- // NOTE
- // Codegen is not implemented so the example above won't be compiled into binary.
- // Instead, some dummy binary will be generated.
-
// Link a static library.
l_static(u, "/lib/x86_64-linux-gnu/libc.a");
// l_static(u, "libtest.a");