summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-07-31 20:13:31 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-07-31 20:13:31 +0200
commit194f3f6cbad70c3a880736bca70e98a2bffe32c4 (patch)
tree171b9ec711788763c8a793db0e0023d0f4a59c66
parent702c89a42eaeac559949c9bcff924399a557b009 (diff)
downloadbxgen-194f3f6cbad70c3a880736bca70e98a2bffe32c4.zip
Provide __ehdr_start symbol for libc
-rwxr-xr-xbxgen.c425
1 files changed, 313 insertions, 112 deletions
diff --git a/bxgen.c b/bxgen.c
index bd8b145..0f6da1c 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -10,6 +10,7 @@
#/
#/ Qualities
#/
+#/ - Compiler backend in the form of a library
#/ - Single source file
#/ - Simple and flexible API
#/ - No external dependencies
@@ -47,6 +48,7 @@
#/ - Sea of Nodes
#/ - Optimization layers
#/ - JIT
+#/ - Debug info
#/ - C compiler and self-compilation
#/ - Meta codegen >:3
#/ - Linker
@@ -68,6 +70,7 @@
#/ - Static libraries
#/ - Dynamic libraries
#/ - Unused dependencies elimination
+#/ - Comprehensive test suite
#/ - Built-in standard library
#/ - Terminal
#/ - Graphics >:3
@@ -231,7 +234,8 @@ enum {
// Calling conventions
- CONV_CDECL = 0,
+ CONV_UNKNOWN = 0,
+ CONV_CDECL,
CONV_STDCALL,
CONV_FASTCALL,
CONV_THISCALL,
@@ -313,9 +317,7 @@ typedef struct {
u8 *occupied;
} Strint_Table;
-typedef struct {
- i64 node;
-} Var;
+typedef i64 Var;
typedef struct {
i64 address;
@@ -371,14 +373,20 @@ typedef struct {
// and has a string name.
typedef struct {
- u16 convention;
- i64 name_size;
- c8 name[MAX_NAME_SIZE]; // TODO use string table
- i64 num_nodes;
- i64 nodes[MAX_NUM_NODES];
- i64 ret_index;
- i64 unit;
- i64 index_in_unit;
+ b8 emit_done;
+ i64 offset;
+} Proc_Codegen;
+
+typedef struct {
+ u16 convention;
+ i64 name_size;
+ c8 name[MAX_NAME_SIZE]; // TODO use string table
+ i64 num_nodes;
+ i64 nodes[MAX_NUM_NODES];
+ i64 ret_index;
+ i64 unit;
+ i64 index_in_unit;
+ Proc_Codegen codegen;
} Proc;
// A compilation unit is a collection of procedures.
@@ -420,6 +428,7 @@ typedef struct {
i64 value;
i64 name_size;
c8 *name;
+ i64 proc;
} Rel_Entry;
typedef struct {
@@ -435,11 +444,9 @@ typedef struct {
// We use one single large memory block for *everything*.
typedef struct {
- // Semantic graph entities
i64 num_entities;
i64 capacity;
Entity *entities;
-
} Pool;
// TEMP Codegen and linker buffers
@@ -515,8 +522,8 @@ 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);
+i64 node_ctrl_call(Pool *pool, i64 target_proc, i64 num_args, Var *args);
+i64 node_ctrl_call_by_name(Pool *pool, i64 name_size, c8 *name, i64 num_args, Var *args);
i64 node_ctrl_ret(Pool *pool, i64 num_values, Var *values);
i64 proc_init(Pool *pool);
@@ -550,24 +557,37 @@ void io_chmod_exe(i64 f, void *user_data);
// Helpers API
//
#ifndef DISABLE_HELPERS
+
+i64 n_ref(i64 proc, i64 node);
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);
+i64 n_call(i64 proc, i64 target_proc, i64 num_args, Var *args);
+i64 n_call_by_name(i64 proc, c8 *name, i64 num_args, Var *args);
i64 n_ret(i64 proc, i64 num_vals, Var *vals);
+
i64 p_new(i64 unit, c8 *name);
i64 p_new_entry(i64 unit);
void p_add(i64 proc, i64 node);
+
i64 u_new();
void u_add(i64 unit, i64 proc);
void u_entry_point(i64 unit, i64 proc);
void u_elf_x86_64(i64 unit, c8 *output_file_name);
+
void l_code(i64 unit, i64 link_unit);
void l_object(i64 unit, c8 *object_library);
void l_static(i64 unit, c8 *static_library);
c8 * l_find(c8 *name);
+
+#define ARGS(...) \
+ (sizeof((Var[]) { __VA_ARGS__ }) / sizeof(Var)), \
+ (Var[]) { __VA_ARGS__ }
+#define N_CALL(proc, target_proc, ...) n_call((proc), (target_proc), ARGS(__VA_ARGS__))
+#define N_CALL_BY_NAME(proc, name, ...) n_call_by_name((proc), (name), ARGS(__VA_ARGS__))
+#define N_RET(proc, ...) n_ret((proc), ARGS(__VA_ARGS__))
+
#endif
// ================================================================
@@ -833,11 +853,23 @@ i64 node_data_i64(Pool *pool, i64 value) {
});
}
-i64 node_ctrl_call(Pool *pool, u16 convention, i64 target_proc, i64 num_args, Var *args) {
+u16 resolve_calling_convention(Pool *pool, i64 proc) {
+ CHECK(pool != NULL, "Invalid arguments",);
+ CHECK(proc != UNDEFINED, "Invalid arguments",);
+ CHECK(pool->entities[proc].is_enabled, "No entity",);
+ CHECK(pool->entities[proc].type == ENTITY_PROC, "No proc",);
+
+ if (pool->entities[proc].proc.convention == CONV_UNKNOWN)
+ pool->entities[proc].proc.convention = CONV_CDECL;
+
+ return pool->entities[proc].proc.convention;
+}
+
+i64 node_ctrl_call(Pool *pool, i64 target_proc, i64 num_args, Var *args) {
CHECK(num_args <= MAX_NUM_ARGS, "Array too big", UNDEFINED);
Call call = {
- .convention = convention,
+ .convention = resolve_calling_convention(pool, target_proc),
.target_proc = target_proc,
.num_args = num_args,
};
@@ -851,11 +883,11 @@ i64 node_ctrl_call(Pool *pool, u16 convention, i64 target_proc, i64 num_args, Va
});
}
-i64 node_ctrl_call_by_name(Pool *pool, u16 convention, i64 name_size, c8 *name, i64 num_args, Var *args) {
+i64 node_ctrl_call_by_name(Pool *pool, i64 name_size, c8 *name, i64 num_args, Var *args) {
CHECK(num_args <= MAX_NUM_ARGS, "Array too big", UNDEFINED);
Call call = {
- .convention = convention,
+ .convention = CONV_CDECL,
.target_proc = UNDEFINED,
.target_name_size = name_size,
.num_args = num_args,
@@ -1756,6 +1788,11 @@ void x86_64_emit_node(
u8 *begin = codegen->buffer_code + codegen->offset_code;
u8 *end = codegen->buffer_code + codegen->max_code_size;
+ #define CHECK_NODE_(node) \
+ CHECK((node) != UNDEFINED, "Internal", 0); \
+ CHECK(pool->entities[(node)].is_enabled, "Internal", 0); \
+ CHECK(pool->entities[(node)].type == ENTITY_NODE, "Internal", 0)
+
switch (n->op) {
case DATA_PTR:
case DATA_I8:
@@ -1766,31 +1803,28 @@ void x86_64_emit_node(
break;
case CTRL_CALL: {
- CHECK(n->call.convention == CONV_CDECL, "Not implemented", 0);
- CHECK(n->call.target_proc == UNDEFINED, "Not implemented", 0);
- CHECK(n->call.target_name_size > 0, "No proc name", 0);
+ CHECK(n->call.convention == CONV_CDECL, "Not implemented", 0);
+ CHECK(n->call.target_proc == UNDEFINED, "Not implemented", 0);
+ CHECK(n->call.target_name_size > 0, "No proc name", 0);
+ CHECK(codegen->num_rels + 2 <= codegen->max_num_rels, "Out of memory", 0);
switch (n->call.num_args) {
case 1: {
- i64 n_arg = n->call.args[0].node;
- CHECK(n_arg != UNDEFINED, "Internal", 0);
- CHECK(pool->entities[n_arg].is_enabled, "Internal", 0);
- CHECK(pool->entities[n_arg].type == ENTITY_NODE, "Internal", 0);
+ i64 n_arg = n->call.args[0];
+ CHECK_NODE_(n_arg);
Node *arg = &pool->entities[n_arg].node;
if (arg->op == DATA_REFERENCE) {
- Node *data = &pool->entities[arg->ref.node].node;
+ // Write data
+ //
+
+ Node *data = &pool->entities[arg->ref].node;
CHECK(data->op == DATA_I8, "Not implemented", 0);
CHECK(codegen->offset_rodata + data->lit.num_bytes <= codegen->max_rodata_size, "Out of memory", 0);
- 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;
+ i64 arg_offset = codegen->offset_rodata;
mem_cpy(codegen->buffer_rodata + arg_offset, data->lit.as_u8, data->lit.num_bytes);
// Write code and relocations
@@ -1804,6 +1838,7 @@ void x86_64_emit_node(
.offset = codegen->offset_code + 2,
.size = 8,
.value = arg_offset,
+ .proc = UNDEFINED, // FIXME use zero value
};
write_u8(LE, 0x48, begin + 10, end); // movabs
@@ -1815,12 +1850,14 @@ void x86_64_emit_node(
.size = 8,
.name_size = n->call.target_name_size,
.name = n->call.target_name,
+ .proc = UNDEFINED, // FIXME use zero value
};
write_u8(LE, 0xff, begin + 20, end); // call
write_u8(LE, 0xd0, begin + 21, end); // rax
- codegen->offset_code += 22;
+ codegen->offset_code += 22;
+ codegen->offset_rodata += data->lit.num_bytes;
} else if (arg->op == DATA_I32) {
CHECK(arg->lit.num_bytes == 4, "Not implemented",);
@@ -1835,6 +1872,7 @@ void x86_64_emit_node(
.size = 8,
.name_size = n->call.target_name_size,
.name = n->call.target_name,
+ .proc = UNDEFINED, // FIXME use zero value
};
write_u8(LE, 0xff, begin + 11, end); // call
@@ -1847,19 +1885,13 @@ void x86_64_emit_node(
} 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;
-
- CHECK(n_arg_0 != UNDEFINED, "Internal", 0);
- CHECK(pool->entities[n_arg_0].is_enabled, "Internal", 0);
- CHECK(pool->entities[n_arg_0].type == ENTITY_NODE, "Internal", 0);
- CHECK(n_arg_1 != UNDEFINED, "Internal", 0);
- CHECK(pool->entities[n_arg_1].is_enabled, "Internal", 0);
- CHECK(pool->entities[n_arg_1].type == ENTITY_NODE, "Internal", 0);
- CHECK(n_arg_2 != UNDEFINED, "Internal", 0);
- CHECK(pool->entities[n_arg_2].is_enabled, "Internal", 0);
- CHECK(pool->entities[n_arg_2].type == ENTITY_NODE, "Internal", 0);
+ i64 n_arg_0 = n->call.args[0];
+ i64 n_arg_1 = n->call.args[1];
+ i64 n_arg_2 = n->call.args[2];
+
+ CHECK_NODE_(n_arg_0);
+ CHECK_NODE_(n_arg_1);
+ CHECK_NODE_(n_arg_2);
Node *arg_0 = &pool->entities[n_arg_0].node;
Node *arg_1 = &pool->entities[n_arg_1].node;
@@ -1887,6 +1919,7 @@ void x86_64_emit_node(
.size = 8,
.name_size = n->call.target_name_size,
.name = n->call.target_name,
+ .proc = UNDEFINED, // FIXME use zero value
};
write_u8(LE, 0xff, begin + 16, end); // call
@@ -1895,6 +1928,122 @@ void x86_64_emit_node(
codegen->offset_code += 18;
} break;
+ case 7: {
+ i64 n_arg_0 = n->call.args[0];
+ i64 n_arg_1 = n->call.args[1];
+ i64 n_arg_2 = n->call.args[2];
+ i64 n_arg_3 = n->call.args[3];
+ i64 n_arg_4 = n->call.args[4];
+ i64 n_arg_5 = n->call.args[5];
+ i64 n_arg_6 = n->call.args[6];
+
+ CHECK_NODE_(n_arg_0);
+ CHECK_NODE_(n_arg_1);
+ CHECK_NODE_(n_arg_2);
+ CHECK_NODE_(n_arg_3);
+ CHECK_NODE_(n_arg_4);
+ CHECK_NODE_(n_arg_5);
+ CHECK_NODE_(n_arg_6);
+
+ 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;
+ Node *arg_3 = &pool->entities[n_arg_3].node;
+ Node *arg_4 = &pool->entities[n_arg_4].node;
+ Node *arg_5 = &pool->entities[n_arg_5].node;
+ Node *arg_6 = &pool->entities[n_arg_6].node;
+
+ CHECK(arg_0->op == DATA_REFERENCE, "Not implemented", 0);
+ CHECK(arg_1->op == DATA_I32, "Not implemented", 0);
+ CHECK(arg_2->op == DATA_REFERENCE, "Not implemented", 0);
+ CHECK(arg_3->op == DATA_PTR, "Not implemented", 0);
+ CHECK(arg_4->op == DATA_PTR, "Not implemented", 0);
+ CHECK(arg_5->op == DATA_PTR, "Not implemented", 0);
+ CHECK(arg_6->op == DATA_PTR, "Not implemented", 0);
+
+ CHECK(arg_0->ref != UNDEFINED, "Internal", 0);
+ CHECK(pool->entities[arg_0->ref].is_enabled, "Internal", 0);
+ CHECK(arg_2->ref != UNDEFINED, "Internal", 0);
+ CHECK(pool->entities[arg_2->ref].is_enabled, "Internal", 0);
+
+ CHECK(pool->entities[arg_0->ref].type == ENTITY_PROC, "Not implemented", 0);
+ CHECK(pool->entities[arg_2->ref].type == ENTITY_NODE, "Not implemented", 0);
+
+ // Write data
+ //
+
+ Node *dat_2 = &pool->entities[arg_2->ref].node;
+ CHECK(dat_2->op == DATA_PTR, "Not implemented", 0);
+
+ CHECK(codegen->offset_rodata + dat_2->lit.num_bytes <= codegen->max_rodata_size, "Out of memory", 0);
+
+ i64 arg_2_offset = codegen->offset_rodata;
+ mem_cpy(codegen->buffer_rodata + arg_2_offset, dat_2->lit.as_u8, dat_2->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_PROC_ADDRESS,
+ .offset = codegen->offset_code + 2,
+ .size = 8,
+ .proc = arg_0->ref,
+ };
+
+ write_u8 (LE, 0xbe, begin + 10, end); // mov esi
+ write_u32(LE, arg_1->lit.as_u32[0], begin + 11, end);
+ write_u8 (LE, 0x48, begin + 15, end); // movabs
+ write_u8 (LE, 0xba, begin + 16, end); // rdx
+
+ codegen->rels[codegen->num_rels++] = (Rel_Entry) {
+ .type = REL_ADD_RODATA_ADDRESS,
+ .offset = codegen->offset_code + 17,
+ .size = 8,
+ .value = arg_2_offset,
+ .proc = UNDEFINED, // FIXME use zero value
+ };
+
+ write_u8 (LE, 0x48, begin + 25, end); // movabs
+ write_u8 (LE, 0xb9, begin + 26, end); // rcx
+ write_u64(LE, arg_3->lit.as_u64[0], begin + 27, end);
+ write_u8 (LE, 0x48, begin + 35, end); // movabs
+ write_u8 (LE, 0xb8, begin + 36, end); // r8
+ write_u64(LE, arg_4->lit.as_u64[0], begin + 37, end);
+ write_u8 (LE, 0x48, begin + 45, end); // movabs
+ write_u8 (LE, 0xb9, begin + 46, end); // r9
+ write_u64(LE, arg_5->lit.as_u64[0], begin + 47, end);
+ write_u8 (LE, 0x48, begin + 55, end); // movabs
+ write_u8 (LE, 0xb8, begin + 56, end); // rax
+ write_u64(LE, arg_6->lit.as_u64[0], begin + 57, end);
+ write_u8 (LE, 0x50, begin + 65, end); // push rax
+
+ write_u8 (LE, 0x48, begin + 66, end); // movabs
+ write_u8 (LE, 0xb8, begin + 67, end); // rax
+
+ codegen->rels[codegen->num_rels++] = (Rel_Entry) {
+ .type = REL_ADD_PROC_ADDRESS,
+ .offset = codegen->offset_code + 68,
+ .size = 8,
+ .name_size = n->call.target_name_size,
+ .name = n->call.target_name,
+ .proc = UNDEFINED, // FIXME use zero value
+ };
+
+ write_u8(LE, 0xff, begin + 76, end); // call
+ write_u8(LE, 0xd0, begin + 77, end); // rax
+
+ write_u8(LE, 0x48, begin + 78, end); // add rsp
+ write_u8(LE, 0x83, begin + 79, end); //
+ write_u8(LE, 0xc4, begin + 80, end); //
+ write_u8(LE, 8, begin + 81, end); // 8
+
+ codegen->offset_code += 82;
+ codegen->offset_rodata += dat_2->lit.num_bytes;
+ } break;
+
default:
FAIL("Not implemented",);
}
@@ -1902,8 +2051,6 @@ void x86_64_emit_node(
case CTRL_RET: {
if ((context & EMIT_ENTRY_PROC) != 0) {
- CHECK(n->ret.num_vals == 1, "Not implemented", 0);
-
write_u8 (LE, 0xb8, begin, end); // mov eax
write_u32(LE, 60, begin + 1, end); // 60
@@ -1915,7 +2062,7 @@ void x86_64_emit_node(
if (n->ret.num_vals > 1)
LOG(WARNING, "Some return values are ignored for node %lld", node);
- i64 n_val = n->ret.vals[0].node;
+ i64 n_val = n->ret.vals[0];
CHECK(n_val != UNDEFINED, "Internal", 0);
CHECK(pool->entities[n_val].is_enabled, "Internal", 0);
CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal", 0);
@@ -1933,13 +2080,30 @@ void x86_64_emit_node(
codegen->offset_code += 12;
} else {
- FAIL("Not implemented",);
+ CHECK(n->ret.num_vals == 1, "Not implemented", 0);
+
+ i64 n_val = n->ret.vals[0];
+ CHECK(n_val != UNDEFINED, "Internal", 0);
+ CHECK(pool->entities[n_val].is_enabled, "Internal", 0);
+ CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal", 0);
+
+ Node *val = &pool->entities[n_val].node;
+ CHECK(val->op == DATA_I32, "Not implemented", 0);
+ CHECK(val->lit.num_bytes == 4, "Not implemented", 0);
+
+ write_u8 (LE, 0xb8, begin, end); // mov eax
+ write_u32(LE, val->lit.as_u32[0], begin + 1, end);
+ write_u8 (LE, 0xc3, begin + 5, end); // ret
+
+ codegen->offset_code += 6;
}
} break;
default:
FAIL("Unknown operation",);
}
+
+ #undef CHECK_NODE_
}
void emit_proc(
@@ -1956,6 +2120,10 @@ void emit_proc(
Proc *p = &pool->entities[proc].proc;
+ CHECK(p->codegen.emit_done == 0, "Emit already done", 0);
+
+ p->codegen.offset = codegen->offset_code;
+
// TODO Sort nodes in the sequential execution order.
//
// NOTE
@@ -1963,6 +2131,8 @@ void emit_proc(
for (i64 i = 0; i < p->num_nodes; ++i)
x86_64_emit_node(pool, codegen, p->nodes[i], context);
+
+ p->codegen.emit_done = 1;
}
void emit_unit(Pool *pool, Codegen_Context *codegen, i64 unit, u16 arch) {
@@ -2681,6 +2851,15 @@ i64 unit_write_in_memory(
// __getf2
// __unordtf2
+ CHECK(num_symbols < linker->max_num_symbols, "Too many symbols",);
+
+ linker->symbols[num_symbols++] = (Symbol_Entry) {
+ .name_size = 12,
+ .name = "__ehdr_start",
+ .address = base_address,
+ .size = ELF_HEADER_SIZE,
+ };
+
// ==============================================================
//
// Apply relocations
@@ -2726,7 +2905,7 @@ i64 unit_write_in_memory(
sym_name,
sym_name + relx.symbol.name.size
) == NULL) {
- // FIXME
+ // FIXME
// LOG(WARNING, "Undefined symbol: %s", sym_name);
CHECK(not_found_size + relx.symbol.name.size + 1 <= linker->max_not_found_size, "Out of memory",);
mem_cpy(linker->not_found_buffer + not_found_size, sym_name, relx.symbol.name.size);
@@ -2769,6 +2948,11 @@ i64 unit_write_in_memory(
// Represents the place (section offset or address) of the Procedure Linkage Table entry for a symbol.
i64 L = S;
+ // if (P >= 0x4018ad && P < 0x4018b2) {
+ // LOG(TRACE, "");
+ // }
+ // LOG(VERBOSE, "--");
+
switch (relx.type) {
#define ADD_(BITS, OP) \
do { \
@@ -2856,19 +3040,35 @@ i64 unit_write_in_memory(
case REL_ADD_PROC_ADDRESS: {
CHECK(rel.size == 8, "Not implemented", 0);
- CHECK(rel.name_size > 0 && rel.name != NULL, "No proc name", 0);
b8 found = 0;
- for (i64 i = 0; i < num_symbols; ++i)
- if (linker->symbols[i].address != 0 &&
- linker->symbols[i].name_size == rel.name_size &&
- 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;
- LOG(VERBOSE, "Found %.*s: 0x%llx", rel.name_size, rel.name, value);
- break;
- }
+
+ if (rel.proc == UNDEFINED) {
+ CHECK(rel.name_size > 0 && rel.name != NULL, "No proc name", 0);
+
+ for (i64 i = 0; i < num_symbols; ++i)
+ if (linker->symbols[i].address != 0 &&
+ linker->symbols[i].name_size == rel.name_size &&
+ 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;
+
+ LOG(VERBOSE, "Found %.*s: 0x%llx", rel.name_size, rel.name, value);
+ break;
+ }
+ } else {
+ CHECK(pool->entities[rel.proc].is_enabled, "No entity", 0);
+ CHECK(pool->entities[rel.proc].type == ENTITY_PROC, "No proc", 0);
+ Proc *p = &pool->entities[rel.proc].proc;
+ CHECK(p->codegen.emit_done, "No proc address", 0);
+
+ i64 value = rel.value + rotext_address + p->codegen.offset;
+ write_i64(LE, value, begin, end);
+ found = 1;
+
+ LOG(VERBOSE, "Found anonymous proc: 0x%llx", value);
+ }
if (!found) {
LOG(ERROR, "Undefined symbol: %.*s", rel.name_size, rel.name);
@@ -3407,6 +3607,12 @@ Linker_Context g_linker = {
// Handy procedures
//
+i64 n_ref(i64 proc, i64 node) {
+ i64 n_ref = node_data_reference(&g_pool, node);
+ p_add(proc, n_ref);
+ return n_ref;
+}
+
i64 n_ptr(i64 proc, u64 address) {
i64 n_data = node_data_ptr(&g_pool, address);
p_add(proc, n_data);
@@ -3434,14 +3640,14 @@ i64 n_i64(i64 proc, i64 value) {
return n;
}
-i64 n_call(i64 proc, u16 convention, i64 target_proc, i64 num_args, Var *args) {
- i64 n = node_ctrl_call(&g_pool, convention, target_proc, num_args, args);
+i64 n_call(i64 proc, i64 target_proc, i64 num_args, Var *args) {
+ i64 n = node_ctrl_call(&g_pool, target_proc, num_args, args);
p_add(proc, n);
return n;
}
-i64 n_call_by_name(i64 proc, u16 convention, c8 *name, i64 num_args, Var *args) {
- i64 n = node_ctrl_call_by_name(&g_pool, convention, bx_str_len(name, name + MAX_NAME_SIZE), name, num_args, args);
+i64 n_call_by_name(i64 proc, c8 *name, i64 num_args, Var *args) {
+ i64 n = node_ctrl_call_by_name(&g_pool, bx_str_len(name, name + MAX_NAME_SIZE), name, num_args, args);
p_add(proc, n);
return n;
}
@@ -3557,53 +3763,48 @@ int main(int argc, char **argv) {
// ============================================================
//
- // Create the program
+ // Create the program semantic tree
// Add a compilation unit.
i64 u = u_new();
+ // Add the main proc.
+ // NOTE We don't need a name for it.
+ i64 mainproc = p_new(u, "");
+ {
+ // Call puts
+ N_CALL_BY_NAME(
+ mainproc,
+ "puts", // proc name
+ n_str(mainproc, "hello sailor") // the first argument
+ );
+
+ // Return 42
+ N_RET(
+ mainproc,
+ n_i32(mainproc, 42) // the return value
+ );
+ }
+
// Add the entry point.
- i64 mainproc = p_new_entry(u);
-
- // 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,
- CONV_CDECL, // calling convention
- "puts", // proc name
- 1, // number of arguments
- (Var[]) {{
- .node = n_str(mainproc, "hello sailor"), // the first argument
- }}
- );
-
- // Return 42
- n_ret(
- mainproc,
- 1, // number of returned values
- (Var[]) {{
- .node = n_i64(mainproc, 42), // the return value
- }}
- );
+ i64 entry = p_new_entry(u);
+ {
+ // Initialize libc
+ N_CALL_BY_NAME(
+ entry,
+ "__libc_start_main",
+ n_ref(entry, mainproc), // main
+ n_i32(entry, 0), // argc
+ n_ref(entry, n_ptr(entry, 0)), // argv
+ n_ptr(entry, 0), // init
+ n_ptr(entry, 0), // fini
+ n_ptr(entry, 0), // rtld_fini
+ n_ptr(entry, 0) // stack_end
+ );
+
+ // Return
+ n_ret(entry, 0, NULL);
+ }
// ============================================================
//