summaryrefslogtreecommitdiff
path: root/bxgen.c
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-07-30 18:46:55 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-07-30 18:46:55 +0200
commit17b966facc1e6e0bf00f12148018587e13088d20 (patch)
tree28b8a4370f9d1d1cec0059d1e39948c649fa7569 /bxgen.c
parent3341c4823a35bb9ca37e2bdc3864ce1ebd78d62c (diff)
downloadbxgen-17b966facc1e6e0bf00f12148018587e13088d20.zip
Init libc
Diffstat (limited to 'bxgen.c')
-rwxr-xr-xbxgen.c340
1 files changed, 237 insertions, 103 deletions
diff --git a/bxgen.c b/bxgen.c
index 204dc0d..2dc657b 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -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,