diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-07-25 10:53:07 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-07-25 10:53:07 +0200 |
commit | fea7c754e443e29b1185fc3cfe50a3c778ccb82b (patch) | |
tree | bf180c9d523e16bd6b9f108b0283f3093c2c64d0 | |
parent | e9934a81f6c69596c0f183abc411804a9d450208 (diff) | |
download | bxgen-fea7c754e443e29b1185fc3cfe50a3c778ccb82b.zip |
Codegen: x86_64 exit syscall
-rwxr-xr-x | bxgen.c | 134 |
1 files changed, 108 insertions, 26 deletions
@@ -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"); |