diff options
Diffstat (limited to 'bxgen.c')
-rwxr-xr-x | bxgen.c | 340 |
1 files changed, 237 insertions, 103 deletions
@@ -193,8 +193,13 @@ enum { // Semantic node operations // - DATA_C8 = 0, + DATA_PTR = 0, + DATA_I8, + DATA_I16, + DATA_I32, DATA_I64, + DATA_F32, + DATA_F64, DATA_REFERENCE, CTRL_CALL, CTRL_RET, @@ -395,7 +400,6 @@ typedef struct { typedef struct { i64 name_size; c8 *name; - i64 section; i64 address; i64 size; } Symbol_Entry; @@ -481,7 +485,10 @@ void pool_remove(Pool *pool, i64 entity, u16 type); i64 node_init(Pool *pool, Node data); void node_destroy(Pool *pool, i64 node); +i64 node_data_reference(Pool *pool, i64 node); i64 node_data_array_c8(Pool *pool, i64 size, c8 *data); +i64 node_data_ptr(Pool *pool, u64 address); +i64 node_data_i32(Pool *pool, i32 value); i64 node_data_i64(Pool *pool, i64 value); i64 node_ctrl_call(Pool *pool, u16 convention, i64 target_proc, i64 num_args, Var *args); i64 node_ctrl_call_by_name(Pool *pool, u16 convention, i64 name_size, c8 *name, i64 num_args, Var *args); @@ -518,7 +525,9 @@ void io_chmod_exe(i64 f, void *user_data); // Helpers API // #ifndef DISABLE_HELPERS +i64 n_ptr(i64 proc, u64 address); i64 n_str(i64 proc, c8 *value); +i64 n_i32(i64 proc, i32 value); i64 n_i64(i64 proc, i64 value); i64 n_call(i64 proc, u16 convention, i64 target_proc, i64 num_args, Var *args); i64 n_call_by_name(i64 proc, u16 convention, c8 *name, i64 num_args, Var *args); @@ -770,13 +779,29 @@ i64 node_data_reference(Pool *pool, i64 node) { i64 node_data_array_c8(Pool *pool, i64 size, c8 *data) { BX_CHECK(size < MAX_LITERAL_SIZE, "Too big", UNDEFINED); Node node_entry = { - .op = DATA_C8, + .op = DATA_I8, .lit.num_bytes = size }; bx_mem_cpy(node_entry.lit.as_u8, data, size); return node_init(pool, node_entry); } +i64 node_data_ptr(Pool *pool, u64 address) { + return node_init(pool, (Node) { + .op = DATA_PTR, + .lit.num_bytes = sizeof address, + .lit.as_u64 = address, + }); +} + +i64 node_data_i32(Pool *pool, i32 value) { + return node_init(pool, (Node) { + .op = DATA_I32, + .lit.num_bytes = sizeof value, + .lit.as_i32 = value, + }); +} + i64 node_data_i64(Pool *pool, i64 value) { return node_init(pool, (Node) { .op = DATA_I64, @@ -1709,7 +1734,9 @@ void x86_64_emit_node( u8 *end = codegen->buffer_code + codegen->max_code_size; switch (n->op) { - case DATA_C8: + case DATA_PTR: + case DATA_I8: + case DATA_I32: case DATA_I64: case DATA_REFERENCE: // Do nothing @@ -1719,59 +1746,135 @@ void x86_64_emit_node( BX_CHECK(n->call.convention == CONV_CDECL, "Not implemented", 0); BX_CHECK(n->call.target_proc == UNDEFINED, "Not implemented", 0); BX_CHECK(n->call.target_name_size > 0, "No proc name", 0); - BX_CHECK(n->call.num_args == 1, "Not implemented", 0); - - i64 n_arg = n->call.args[0].node; - BX_CHECK(n_arg != UNDEFINED, "Internal", 0); - BX_CHECK(pool->entities[n_arg].is_enabled, "Internal", 0); - BX_CHECK(pool->entities[n_arg].type == ENTITY_NODE, "Internal", 0); - - Node *ref = &pool->entities[n_arg].node; - BX_CHECK(ref->op == DATA_REFERENCE, "Not implemented", 0); - - Node *data = &pool->entities[ref->ref.node].node; - BX_CHECK(data->op == DATA_C8, "Not implemented", 0); - - BX_CHECK(codegen->offset_rodata + data->lit.num_bytes <= codegen->max_rodata_size, "Out of memory", 0); - BX_CHECK(codegen->num_rels + 2 <= codegen->max_num_rels, "Out of memory", 0); - - // Write data - // - - i64 arg_offset = codegen->offset_rodata; - codegen->offset_rodata += data->lit.num_bytes; - bx_mem_cpy(codegen->buffer_rodata + arg_offset, data->lit.as_u8, data->lit.num_bytes); - - // Write code and relocations - // - - write_u8(LE, 0x48, begin, end); // movabs - write_u8(LE, 0xbf, begin + 1, end); // rdi - - codegen->rels[codegen->num_rels++] = (Rel_Entry) { - .type = REL_ADD_RODATA_ADDRESS, - .offset = codegen->offset_code + 2, - .size = 8, - .value = arg_offset, - }; - write_u8(LE, 0x31, begin + 10, end); // xor eax - write_u8(LE, 0xc0, begin + 11, end); // eax - write_u8(LE, 0x48, begin + 12, end); // movabs - write_u8(LE, 0xba, begin + 13, end); // rdx + switch (n->call.num_args) { + case 1: { + i64 n_arg = n->call.args[0].node; + BX_CHECK(n_arg != UNDEFINED, "Internal", 0); + BX_CHECK(pool->entities[n_arg].is_enabled, "Internal", 0); + BX_CHECK(pool->entities[n_arg].type == ENTITY_NODE, "Internal", 0); + + Node *arg = &pool->entities[n_arg].node; + + if (arg->op == DATA_REFERENCE) { + Node *data = &pool->entities[arg->ref.node].node; + BX_CHECK(data->op == DATA_I8, "Not implemented", 0); + + BX_CHECK(codegen->offset_rodata + data->lit.num_bytes <= codegen->max_rodata_size, "Out of memory", 0); + BX_CHECK(codegen->num_rels + 2 <= codegen->max_num_rels, "Out of memory", 0); + + // Write data + // + + i64 arg_offset = codegen->offset_rodata; + codegen->offset_rodata += data->lit.num_bytes; + bx_mem_cpy(codegen->buffer_rodata + arg_offset, data->lit.as_u8, data->lit.num_bytes); + + // Write code and relocations + // + + write_u8(LE, 0x48, begin, end); // movabs + write_u8(LE, 0xbf, begin + 1, end); // rdi + + codegen->rels[codegen->num_rels++] = (Rel_Entry) { + .type = REL_ADD_RODATA_ADDRESS, + .offset = codegen->offset_code + 2, + .size = 8, + .value = arg_offset, + }; + + write_u8(LE, 0x48, begin + 10, end); // movabs + write_u8(LE, 0xb8, begin + 11, end); // rax + + codegen->rels[codegen->num_rels++] = (Rel_Entry) { + .type = REL_ADD_PROC_ADDRESS, + .offset = codegen->offset_code + 12, + .size = 8, + .name_size = n->call.target_name_size, + .name = n->call.target_name, + }; + + write_u8(LE, 0xff, begin + 20, end); // call + write_u8(LE, 0xd0, begin + 21, end); // rax + + codegen->offset_code += 22; + } else if (arg->op == DATA_I32) { + BX_CHECK(arg->lit.num_bytes == 4, "Not implemented",); + + write_u8 (LE, 0xbf, begin, end); // mov edi + write_i32(LE, arg->lit.as_i32[0], begin + 1, end); + write_u8 (LE, 0x48, begin + 5, end); // movabs + write_u8 (LE, 0xb8, begin + 6, end); // rax + + codegen->rels[codegen->num_rels++] = (Rel_Entry) { + .type = REL_ADD_PROC_ADDRESS, + .offset = codegen->offset_code + 7, + .size = 8, + .name_size = n->call.target_name_size, + .name = n->call.target_name, + }; + + write_u8(LE, 0xff, begin + 11, end); // call + write_u8(LE, 0xd0, begin + 12, end); // rax + + codegen->offset_code += 13; + } else { + BX_FAIL("Not implemented",); + } + } break; + + case 3: { + i64 n_arg_0 = n->call.args[0].node; + i64 n_arg_1 = n->call.args[1].node; + i64 n_arg_2 = n->call.args[2].node; + + BX_CHECK(n_arg_0 != UNDEFINED, "Internal", 0); + BX_CHECK(pool->entities[n_arg_0].is_enabled, "Internal", 0); + BX_CHECK(pool->entities[n_arg_0].type == ENTITY_NODE, "Internal", 0); + BX_CHECK(n_arg_1 != UNDEFINED, "Internal", 0); + BX_CHECK(pool->entities[n_arg_1].is_enabled, "Internal", 0); + BX_CHECK(pool->entities[n_arg_1].type == ENTITY_NODE, "Internal", 0); + BX_CHECK(n_arg_2 != UNDEFINED, "Internal", 0); + BX_CHECK(pool->entities[n_arg_2].is_enabled, "Internal", 0); + BX_CHECK(pool->entities[n_arg_2].type == ENTITY_NODE, "Internal", 0); + + Node *arg_0 = &pool->entities[n_arg_0].node; + Node *arg_1 = &pool->entities[n_arg_1].node; + Node *arg_2 = &pool->entities[n_arg_2].node; + + BX_CHECK(arg_0->op == DATA_PTR, "Not implemented", 0); + BX_CHECK(arg_1->op == DATA_PTR, "Not implemented", 0); + BX_CHECK(arg_2->op == DATA_PTR, "Not implemented", 0); + BX_CHECK(arg_0->lit.as_u64[0] == 0, "Not implemented", 0); + BX_CHECK(arg_1->lit.as_u64[0] == 0, "Not implemented", 0); + BX_CHECK(arg_2->lit.as_u64[0] == 0, "Not implemented", 0); + + write_u8(LE, 0x31, begin, end); // xor edx + write_u8(LE, 0xd2, begin + 1, end); // edx + write_u8(LE, 0x31, begin + 2, end); // xor esi + write_u8(LE, 0xf6, begin + 3, end); // esi + write_u8(LE, 0x31, begin + 4, end); // xor edi + write_u8(LE, 0xff, begin + 5, end); // edi + write_u8(LE, 0x48, begin + 6, end); // movabs + write_u8(LE, 0xb8, begin + 7, end); // rax + + codegen->rels[codegen->num_rels++] = (Rel_Entry) { + .type = REL_ADD_PROC_ADDRESS, + .offset = codegen->offset_code + 8, + .size = 8, + .name_size = n->call.target_name_size, + .name = n->call.target_name, + }; - codegen->rels[codegen->num_rels++] = (Rel_Entry) { - .type = REL_ADD_PROC_ADDRESS, - .offset = codegen->offset_code + 14, - .size = 8, - .name_size = n->call.target_name_size, - .name = n->call.target_name, - }; + write_u8(LE, 0xff, begin + 16, end); // call + write_u8(LE, 0xd0, begin + 17, end); // rax - write_u8(LE, 0xff, begin + 22, end); // call - write_u8(LE, 0xd2, begin + 23, end); // rdx + codegen->offset_code += 18; + } break; - codegen->offset_code += 24; + default: + BX_FAIL("Not implemented",); + } } break; case CTRL_RET: { @@ -2360,7 +2463,7 @@ i64 unit_write_in_memory( i64 rotext_address = base_address + program_offset; i64 entry = rotext_address + codegen->entry_point; - BX_LOG(VERBOSE, "Entry point: 0x%08llx (%lld)", entry, entry); + BX_LOG(VERBOSE, "Entry point: 0x%llx (%lld)", entry, entry); i64 rotext_size = codegen->offset_code; i64 rwzval_size = 0; @@ -2492,7 +2595,6 @@ i64 unit_write_in_memory( linker->symbols[num_symbols++] = (Symbol_Entry) { .name_size = sym.name.size, .name = sym_name, - .section = sym_section, .address = sym_address, .size = sym.value.size, }; @@ -2594,7 +2696,7 @@ i64 unit_write_in_memory( symbol = linker->symbols[i]; break; } - if (symbol.name_size == 0 && + if (symbol.address == 0 && bx_find_str_in_table( linker->not_found_buffer, linker->not_found_buffer + not_found_size, @@ -2611,7 +2713,6 @@ i64 unit_write_in_memory( i64 src_index_global = sec_index_global + relx.symbol.section - 1; symbol = (Symbol_Entry) { - .section = src_index_global, .address = relx.symbol.value.offset + linker->section_addresses[src_index_global], .size = relx.symbol.value.size, }; @@ -2637,7 +2738,7 @@ i64 unit_write_in_memory( i64 Z = symbol.size; // Represents the address of the global offset table. - i64 GOT = 0; + i64 GOT = S; // Represents the offset into the global offset table at which the relocation entry's symbol will reside during execution. i64 G = 0; @@ -2654,48 +2755,49 @@ i64 unit_write_in_memory( #define TODO_ BX_FAIL("Not implemented", 0) - case R_X86_64_NONE: /* Do nothing */ break; - case R_X86_64_64: ADD_(64, 0); break; // 64, S + A - case R_X86_64_PC32: ADD_(32, S + A - P); break; // 32, S + A - P - case R_X86_64_GOT32: TODO_; break; // 32, G + A - case R_X86_64_PLT32: ADD_(32, L + A - P); break; // 32, L + A - P - case R_X86_64_COPY: /* Do nothing */ break; - case R_X86_64_GLOB_DAT: TODO_; break; // 64, S - case R_X86_64_JUMP_SLOT: TODO_; break; // 64, S - case R_X86_64_RELATIVE: TODO_; break; // 64, B + A - case R_X86_64_GOTPCREL: ADD_(32, 0); break; // 32, G + GOT + A - P - case R_X86_64_32: TODO_; break; // 32, S + A - case R_X86_64_32S: TODO_; break; // 32, S + A - case R_X86_64_16: TODO_; break; // 16, S + A - case R_X86_64_PC16: TODO_; break; // 16, S + A - P - case R_X86_64_8: TODO_; break; // 8, S + A - case R_X86_64_PC8: TODO_; break; // 8, S + A - P - case R_X86_64_DTPMOD64: TODO_; break; - case R_X86_64_DTPOFF64: TODO_; break; - case R_X86_64_TPOFF64: TODO_; break; - case R_X86_64_TLSGD: TODO_; break; - case R_X86_64_TLSLD: TODO_; break; - case R_X86_64_DTPOFF32: TODO_; break; - case R_X86_64_GOTTPOFF: ADD_(32, 0); break; // 32, S - GOT - case R_X86_64_TPOFF32: ADD_(32, 0); break; // 32, S + A - B - case R_X86_64_PC64: TODO_; break; // 64, S + A - P - case R_X86_64_GOTOFF64: TODO_; break; - case R_X86_64_GOTPC32: TODO_; break; // 32, GOT + A - P - case R_X86_64_GOT64: TODO_; break; - case R_X86_64_GOTPCREL64: TODO_; break; - case R_X86_64_GOTPC64: TODO_; break; // 64, GOT + A - P - case R_X86_64_GOTPLT64: TODO_; break; - case R_X86_64_PLTOFF64: TODO_; break; - case R_X86_64_SIZE32: TODO_; break; // 32, Z + A - case R_X86_64_SIZE64: TODO_; break; // 64, Z + A - case R_X86_64_GOTPC32_TLSDESC: TODO_; break; - case R_X86_64_TLSDESC_CALL: TODO_; break; - case R_X86_64_TLSDESC: TODO_; break; - case R_X86_64_IRELATIVE: TODO_; break; - case R_X86_64_RELATIVE64: TODO_; break; - case R_X86_64_GOTPCRELX: TODO_; break; - case R_X86_64_REX_GOTPCRELX: ADD_(32, 0); break; // 32, GOT - P + G - 4 - default: BX_LAX(0, "Unknown relocation type"); + case R_X86_64_NONE: /* Do nothing */ break; + case R_X86_64_64: ADD_(64, S + A); break; // 64, S + A + case R_X86_64_PC32: ADD_(32, S + A - P); break; // 32, S + A - P + case R_X86_64_GOT32: TODO_; break; // 32, G + A + case R_X86_64_PLT32: ADD_(32, L + A - P); break; // 32, L + A - P + case R_X86_64_COPY: /* Do nothing */ break; + case R_X86_64_GLOB_DAT: TODO_; break; // 64, S + case R_X86_64_JUMP_SLOT: TODO_; break; // 64, S + case R_X86_64_RELATIVE: TODO_; break; // 64, B + A + case R_X86_64_GOTPCREL: ADD_(32, G + GOT + A - P); break; // 32, G + GOT + A - P + case R_X86_64_32: TODO_; break; // 32, S + A + case R_X86_64_32S: TODO_; break; // 32, S + A + case R_X86_64_16: TODO_; break; // 16, S + A + case R_X86_64_PC16: TODO_; break; // 16, S + A - P + case R_X86_64_8: TODO_; break; // 8, S + A + case R_X86_64_PC8: TODO_; break; // 8, S + A - P + case R_X86_64_DTPMOD64: TODO_; break; + case R_X86_64_DTPOFF64: TODO_; break; + case R_X86_64_TPOFF64: TODO_; break; + case R_X86_64_TLSGD: TODO_; break; + case R_X86_64_TLSLD: TODO_; break; + case R_X86_64_DTPOFF32: TODO_; break; + case R_X86_64_GOTTPOFF: ADD_(32, S - GOT); break; // 32, S - GOT + case R_X86_64_TPOFF32: ADD_(32, S + A - B); break; // 32, S + A - B + case R_X86_64_PC64: TODO_; break; // 64, S + A - P + case R_X86_64_GOTOFF64: TODO_; break; + case R_X86_64_GOTPC32: TODO_; break; // 32, GOT + A - P + case R_X86_64_GOT64: TODO_; break; + case R_X86_64_GOTPCREL64: TODO_; break; + case R_X86_64_GOTPC64: TODO_; break; // 64, GOT + A - P + case R_X86_64_GOTPLT64: TODO_; break; + case R_X86_64_PLTOFF64: TODO_; break; + case R_X86_64_SIZE32: TODO_; break; // 32, Z + A + case R_X86_64_SIZE64: TODO_; break; // 64, Z + A + case R_X86_64_GOTPC32_TLSDESC: TODO_; break; + case R_X86_64_TLSDESC_CALL: TODO_; break; + case R_X86_64_TLSDESC: TODO_; break; + case R_X86_64_IRELATIVE: TODO_; break; + case R_X86_64_RELATIVE64: TODO_; break; + case R_X86_64_GOTPCRELX: TODO_; break; + case R_X86_64_REX_GOTPCRELX: ADD_(32, GOT - P + G - 4); break; // 32, GOT - P + G - 4 + + default: BX_FAIL("Unknown relocation type", 0); #undef ADD_ #undef TODO_ @@ -2735,13 +2837,13 @@ i64 unit_write_in_memory( b8 found = 0; for (i64 i = 0; i < num_symbols; ++i) - if (linker->symbols[i].section != 0 && + if (linker->symbols[i].address != 0 && linker->symbols[i].name_size == rel.name_size && bx_mem_eq(linker->symbols[i].name, rel.name, rel.name_size)) { i64 value = rel.value + linker->symbols[i].address; write_i64(LE, value, begin, end); found = 1; - BX_LOG(VERBOSE, "Found %.*s: 0x%08llx", rel.name_size, rel.name, value); + BX_LOG(VERBOSE, "Found %.*s: 0x%llx", rel.name_size, rel.name, value); break; } @@ -2867,7 +2969,7 @@ i64 unit_write_in_memory( for (i64 sec_index = 1; sec_index < headers.num; ++sec_index, ++sec_index_global) { Elf_Section_Header section = elf_section(buf, sec_index); - i64 offset = linker->section_offsets[sec_index_global]; + i64 offset = linker->section_offsets[sec_index_global]; if (offset == 0 || !section.alloc || section.data.size == 0) @@ -3282,6 +3384,12 @@ Linker_Context g_linker = { // Handy procedures // +i64 n_ptr(i64 proc, u64 address) { + i64 n_data = node_data_ptr(&g_pool, address); + p_add(proc, n_data); + return n_data; +} + i64 n_str(i64 proc, c8 *value) { i64 len = bx_str_len(value, value + MAX_LITERAL_SIZE - 1); i64 n_data = node_data_array_c8(&g_pool, len + 1, value); @@ -3291,6 +3399,12 @@ i64 n_str(i64 proc, c8 *value) { return n_ref; } +i64 n_i32(i64 proc, i32 value) { + i64 n = node_data_i32(&g_pool, value); + p_add(proc, n); + return n; +} + i64 n_i64(i64 proc, i64 value) { i64 n = node_data_i64(&g_pool, value); p_add(proc, n); @@ -3424,6 +3538,26 @@ int main(int argc, char **argv) { // Add the `main` procedure. i64 mainproc = p_new_entry(u, "main"); + // Initialize libc + n_call_by_name( + mainproc, + CONV_CDECL, + "__libc_early_init", + 1, + (Var[]) {{ .node = n_i32(mainproc, 1), }} + ); + n_call_by_name( + mainproc, + CONV_CDECL, + "__libc_init_first", + 3, + (Var[]) { + { .node = n_ptr(mainproc, 0), }, + { .node = n_ptr(mainproc, 0), }, + { .node = n_ptr(mainproc, 0), }, + } + ); + // Call puts n_call_by_name( mainproc, |