diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-07-31 20:13:31 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-07-31 20:13:31 +0200 |
commit | 194f3f6cbad70c3a880736bca70e98a2bffe32c4 (patch) | |
tree | 171b9ec711788763c8a793db0e0023d0f4a59c66 | |
parent | 702c89a42eaeac559949c9bcff924399a557b009 (diff) | |
download | bxgen-194f3f6cbad70c3a880736bca70e98a2bffe32c4.zip |
Provide __ehdr_start symbol for libc
-rwxr-xr-x | bxgen.c | 425 |
1 files changed, 313 insertions, 112 deletions
@@ -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); + } // ============================================================ // |