diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-22 12:56:34 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-22 12:56:34 +0100 |
commit | 09e6e123d803c7587464e29532dc61a025f517d5 (patch) | |
tree | 7180bfaddd91b4130c46ceb8e711ab00635d15e5 /bxgen.c | |
parent | b3c47026b79d0d9ce46bb1f1dbb4f7c6b652e758 (diff) | |
download | bxgen-09e6e123d803c7587464e29532dc61a025f517d5.zip |
Add addition tests
Diffstat (limited to 'bxgen.c')
-rwxr-xr-x | bxgen.c | 1353 |
1 files changed, 1065 insertions, 288 deletions
@@ -346,9 +346,9 @@ typedef struct { } Ret; typedef struct { - // NOTE - // We may call a local procedure by it's id, - // or a global procedure by name. + // NOTE + // We may call a local procedure by it's id, + // or a global procedure by name. u16 convention; // can be implicitly retrieved from the procedure i64 target_proc; @@ -377,20 +377,14 @@ typedef struct { // and has a string name. typedef struct { - 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; + 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; // A compilation unit is a collection of procedures. @@ -425,6 +419,27 @@ typedef struct { }; } Entity; +// Pool, a collection of all entities. +// +// NOTE +// We use one single large memory block for *everything*. + +typedef struct { + i64 num_entities; + i64 capacity; + Entity *entities; +} Pool; + +// TEMP Codegen and linker buffers +// TODO Use string table for buffers also. + +typedef struct { + b8 emit_done; + i64 offset; + i64 reg; + u64 occupied_reg; +} Codegen_Entity; + typedef struct { u16 type; i64 offset; @@ -433,7 +448,7 @@ typedef struct { i64 name_size; c8 *name; i64 proc; -} Rel_Entry; +} Codegen_Rel_Entry; typedef struct { i64 offset; @@ -454,32 +469,19 @@ typedef struct { i64 symbol; } Link_Rel_Entry; -// Pool, a collection of all entities. -// -// NOTE -// We use one single large memory block for *everything*. - -typedef struct { - i64 num_entities; - i64 capacity; - Entity *entities; -} Pool; - -// TEMP Codegen and linker buffers -// TODO Use string table for buffers also. - typedef struct { - i64 max_num_rels; - i64 max_code_size; - i64 max_ro_data_size; - b8 has_entry; - i64 entry_point; - i64 num_rels; - i64 offset_code; - i64 offset_ro_data; - Rel_Entry *rels; - u8 * buffer_code; - u8 * buffer_ro_data; + i64 max_num_rels; + i64 max_code_size; + i64 max_ro_data_size; + b8 has_entry; + i64 entry_point; + i64 num_rels; + i64 offset_code; + i64 offset_ro_data; + Codegen_Entity * entities; + Codegen_Rel_Entry *rels; + u8 * buffer_code; + u8 * buffer_ro_data; } Codegen_Context; typedef struct { @@ -643,8 +645,13 @@ c8 * l_find(c8 *name, b8 silent); } \ } while (0) #else -# define CHECK(condition, error_string, fail_result) \ - dispatch_assert((condition), error_string, __LINE__, __FILE__) +# define CHECK(condition, error_string, fail_result) \ + do { \ + b8 ok_ = (condition); \ + dispatch_assert(ok_, error_string, __LINE__, __FILE__); \ + if (!ok_) \ + return fail_result; \ + } while (0) #endif #ifdef NDEBUG @@ -812,6 +819,7 @@ i64 pool_add(Pool *pool, Entity data) { data.is_enabled = 1, pool->entities[id] = data; + CHECK(id != UNDEFINED, "Sanity", UNDEFINED); return id; } @@ -889,10 +897,10 @@ i64 node_data_add(Pool *pool, Var x, Var y) { } 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",); + CHECK(pool != NULL, "Invalid arguments", 0); + CHECK(proc != UNDEFINED, "Invalid arguments", 9); + CHECK(pool->entities[proc].is_enabled, "No entity", 0); + CHECK(pool->entities[proc].type == ENTITY_PROC, "No proc", 0); if (pool->entities[proc].proc.convention == CONV_UNKNOWN) pool->entities[proc].proc.convention = CONV_CDECL; @@ -1577,6 +1585,8 @@ enum { X86_64_BASE_ADDRESS = 0x400000, X86_64_ALIGNMENT = 8, + + // NOTE For compatibility with Box64 on ARM X86_64_PAGE_SIZE = 16 * 1024, // 4 * 1024 // ELF format constants @@ -1830,22 +1840,25 @@ typedef struct { void x86_64_emit_node( Pool * pool, Codegen_Context *codegen, + Codegen_Entity *proc, i64 node, u32 context ) { - CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0); - CHECK(node != UNDEFINED && pool->entities[node].is_enabled, "No node", 0); - CHECK(pool->entities[node].type == ENTITY_NODE, "Invalid entity", 0); + // TODO Log generated asm. + + CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments",); + CHECK(node != UNDEFINED && pool->entities[node].is_enabled, "No node",); + CHECK(pool->entities[node].type == ENTITY_NODE, "Invalid entity",); Node *n = &pool->entities[node].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) + #define CHECK_NODE_(node_) \ + CHECK((node_) != UNDEFINED, "Internal",); \ + CHECK(pool->entities[(node_)].is_enabled, "Internal",); \ + CHECK(pool->entities[(node_)].type == ENTITY_NODE, "Internal",) switch (n->op) { case DATA_PTR: @@ -1856,35 +1869,713 @@ void x86_64_emit_node( // Do nothing break; - case DATA_ADD: + case DATA_ADD: { + // NOTE Assuming static single-assignment form. + CHECK_NODE_(n->add[0]); CHECK_NODE_(n->add[1]); Node *x = &pool->entities[n->add[0]].node; Node *y = &pool->entities[n->add[1]].node; - if (x->op == DATA_I32) { - write_u8 (LE, 0xb8, begin, end); // mov eax - write_u32(LE, x->lit.as_u32[0], begin + 1, end); - } else { - FAIL("Not implemented",); - } + i64 dst_reg = 1; + while (dst_reg <= 4 && ((1 << (dst_reg - 1)) & proc->occupied_reg) != 0) + ++dst_reg; - if (y->op == DATA_I32) { - write_u8 (LE, 0x05, begin + 5, end); // add eax - write_u32(LE, y->lit.as_u32[0], begin + 6, end); - } else { - FAIL("Not implemented",); + switch (dst_reg) { + case 1: { + // eax + + switch (x->op) { + case DATA_I32: { + write_u8 (LE, 0xb8, begin, end); // mov eax + write_u32(LE, x->lit.as_u32[0], begin + 1, end); + + begin += 5; + codegen->offset_code += 5; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[0]].reg; + + switch (src_reg) { + case 1: + FAIL("Not implemented",); + // eax + break; + + case 2: + FAIL("Not implemented",); + // ebx + + write_u8(LE, 0x89, begin, end); // mov eax + write_u8(LE, 0xd8, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + // ecx + + write_u8(LE, 0x89, begin, end); // mov eax + write_u8(LE, 0xc8, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + + case 4: + // edx + + write_u8(LE, 0x89, begin, end); // mov eax + write_u8(LE, 0xd0, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[0]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + write_u8 (LE, 0x05, begin, end); // add eax + write_u32(LE, y->lit.as_u32[0], begin + 1, end); + + codegen->offset_code += 5; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[1]].reg; + + switch (src_reg) { + case 1: + FAIL("Not implemented",); + // eax + + write_u8(LE, 0x01, begin, end); // add eax + write_u8(LE, 0xc0, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + + write_u8(LE, 0x01, begin, end); // add eax + write_u8(LE, 0xd8, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + // ecx + + write_u8(LE, 0x01, begin, end); // add eax + write_u8(LE, 0xc8, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + case 4: + // edx + + write_u8(LE, 0x01, begin, end); // add eax + write_u8(LE, 0xd0, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[1]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + case 2: { + // ebx + + switch (x->op) { + case DATA_I32: { + write_u8 (LE, 0xbb, begin, end); // mov ebx + write_u32(LE, x->lit.as_u32[0], begin + 1, end); + + begin += 5; + codegen->offset_code += 5; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[0]].reg; + + switch (src_reg) { + case 1: + // eax + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xc3, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xcb, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + + case 4: + // edx + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xd3, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + case 5: + // esi + + write_u8(LE, 0x89, begin, end); // mov ebx + write_u8(LE, 0xf3, begin + 1, end); // esi + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[0]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + write_u8 (LE, 0x81, begin, end); // add ebx + write_u8 (LE, 0xc3, begin + 1, end); + write_u32(LE, y->lit.as_u32[0], begin + 2, end); + + codegen->offset_code += 6; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[1]].reg; + + switch (src_reg) { + case 1: + // eax + + write_u8(LE, 0x01, begin, end); // add ebx + write_u8(LE, 0xc3, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + + write_u8(LE, 0x01, begin, end); // add ebx + write_u8(LE, 0xdb, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x01, begin, end); // add ebx + write_u8(LE, 0xcb, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + + case 4: + FAIL("Not implemented",); + // edx + + write_u8(LE, 0x01, begin, end); // add ebx + write_u8(LE, 0xd3, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[1]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + case 3: { + // ecx + + switch (x->op) { + case DATA_I32: { + write_u8 (LE, 0xb9, begin, end); // mov ecx + write_u32(LE, x->lit.as_u32[0], begin + 1, end); + + begin += 5; + codegen->offset_code += 5; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[0]].reg; + + switch (src_reg) { + case 1: + // eax + + write_u8(LE, 0x89, begin, end); // mov ecx + write_u8(LE, 0xc1, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + + write_u8(LE, 0x89, begin, end); // mov ecx + write_u8(LE, 0xd9, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + break; + + + case 4: + FAIL("Not implemented",); + // edx + + write_u8(LE, 0x89, begin, end); // mov ecx + write_u8(LE, 0xd1, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[0]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + write_u8 (LE, 0x81, begin, end); // add ecx + write_u8 (LE, 0xc1, begin + 1, end); + write_u32(LE, y->lit.as_u32[0], begin + 2, end); + + codegen->offset_code += 6; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[1]].reg; + + switch (src_reg) { + case 1: + FAIL("Not implemented",); + // eax + + write_u8(LE, 0x01, begin, end); // add ecx + write_u8(LE, 0xc1, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + // ebx + + write_u8(LE, 0x01, begin, end); // add ecx + write_u8(LE, 0xd9, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x01, begin, end); // add ecx + write_u8(LE, 0xc9, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + + case 4: + FAIL("Not implemented",); + // edx + + write_u8(LE, 0x01, begin, end); // add ecx + write_u8(LE, 0xd1, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[1]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + case 4: { + // edx + + switch (x->op) { + case DATA_I32: { + write_u8 (LE, 0xba, begin, end); // mov edx + write_u32(LE, x->lit.as_u32[0], begin + 1, end); + + begin += 5; + codegen->offset_code += 5; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[0]].reg; + + switch (src_reg) { + case 1: + // eax + + write_u8(LE, 0x89, begin, end); // mov edx + write_u8(LE, 0xc2, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + + write_u8(LE, 0x89, begin, end); // mov edx + write_u8(LE, 0xda, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x89, begin, end); // mov edx + write_u8(LE, 0xca, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + case 4: + FAIL("Not implemented",); + // edx + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[0]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + write_u8 (LE, 0x81, begin, end); // add edx + write_u8 (LE, 0xc2, begin + 1, end); + write_u32(LE, y->lit.as_u32[0], begin + 2, end); + + codegen->offset_code += 6; + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[1]].reg; + + switch (src_reg) { + case 1: + FAIL("Not implemented",); + // eax + + write_u8(LE, 0x01, begin, end); // add edx + write_u8(LE, 0xc2, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + // ebx + + write_u8(LE, 0x01, begin, end); // add edx + write_u8(LE, 0xda, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x01, begin, end); // add edx + write_u8(LE, 0xca, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + case 4: + FAIL("Not implemented",); + // edx + + write_u8(LE, 0x01, begin, end); // add edx + write_u8(LE, 0xd2, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[1]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + case 5: { + // esi + + switch (x->op) { + case DATA_I32: { + FAIL("Not implemented",); + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[0]].reg; + + switch (src_reg) { + case 1: + // eax + + write_u8(LE, 0x89, begin, end); // mov esi + write_u8(LE, 0xc6, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + FAIL("Not implemented",); + // ebx + + write_u8(LE, 0x89, begin, end); // mov esi + write_u8(LE, 0xde, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x89, begin, end); // mov esi + write_u8(LE, 0xce, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + case 4: + FAIL("Not implemented",); + // edx + + write_u8(LE, 0x89, begin, end); // mov esi + write_u8(LE, 0xd6, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[0]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + + switch (y->op) { + case DATA_I32: { + FAIL("Not implemented",); + } break; + + case DATA_ADD: { + i64 src_reg = codegen->entities[n->add[1]].reg; + + switch (src_reg) { + case 1: + FAIL("Not implemented",); + // eax + + write_u8(LE, 0x01, begin, end); // add esi + write_u8(LE, 0xc6, begin + 1, end); // eax + + begin += 2; + codegen->offset_code += 2; + break; + + case 2: + // ebx + + write_u8(LE, 0x01, begin, end); // add esi + write_u8(LE, 0xde, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + FAIL("Not implemented",); + // ecx + + write_u8(LE, 0x01, begin, end); // add esi + write_u8(LE, 0xce, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + + case 4: + FAIL("Not implemented",); + // edx + + write_u8(LE, 0x01, begin, end); // add esi + write_u8(LE, 0xd6, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + + codegen->entities[n->add[1]].reg = 0; + proc->occupied_reg &= ~(1 << (src_reg - 1)); + } break; + + default: + FAIL("Not implemented",); + } + } break; + + default: + FAIL("Not implemented",); } - codegen->offset_code += 10; - break; + codegen->entities[node].reg = dst_reg; + proc->occupied_reg |= 1 << (dst_reg - 1); + } 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(codegen->num_rels + 2 <= codegen->max_num_rels, "Out of memory", 0); + CHECK(n->call.convention == CONV_CDECL, "Not implemented",); + CHECK(n->call.target_proc == UNDEFINED, "Not implemented",); + CHECK(n->call.target_name_size > 0, "No proc name",); + CHECK(codegen->num_rels + 2 <= codegen->max_num_rels, "Out of memory",); switch (n->call.num_args) { case 1: { @@ -1898,9 +2589,9 @@ void x86_64_emit_node( // Node *data = &pool->entities[arg->ref].node; - CHECK(data->op == DATA_I8, "Not implemented", 0); + CHECK(data->op == DATA_I8, "Not implemented",); - CHECK(codegen->offset_ro_data + data->lit.num_bytes <= codegen->max_ro_data_size, "Out of memory", 0); + CHECK(codegen->offset_ro_data + data->lit.num_bytes <= codegen->max_ro_data_size, "Out of memory",); i64 arg_offset = codegen->offset_ro_data; mem_cpy(codegen->buffer_ro_data + arg_offset, data->lit.as_u8, data->lit.num_bytes); @@ -1911,7 +2602,7 @@ void x86_64_emit_node( write_u8(LE, 0x48, begin, end); // movabs write_u8(LE, 0xbf, begin + 1, end); // rdi - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_RO_DATA_ADDRESS, .offset = codegen->offset_code + 2, .size = 8, @@ -1922,7 +2613,7 @@ void x86_64_emit_node( write_u8(LE, 0x48, begin + 10, end); // movabs write_u8(LE, 0xb8, begin + 11, end); // rax - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_PROC_ADDRESS, .offset = codegen->offset_code + 12, .size = 8, @@ -1944,7 +2635,7 @@ void x86_64_emit_node( write_u8 (LE, 0x48, begin + 5, end); // movabs write_u8 (LE, 0xb8, begin + 6, end); // rax - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_PROC_ADDRESS, .offset = codegen->offset_code + 7, .size = 8, @@ -1975,12 +2666,12 @@ void x86_64_emit_node( Node *arg_1 = &pool->entities[n_arg_1].node; Node *arg_2 = &pool->entities[n_arg_2].node; - CHECK(arg_0->op == DATA_PTR, "Not implemented", 0); - CHECK(arg_1->op == DATA_PTR, "Not implemented", 0); - CHECK(arg_2->op == DATA_PTR, "Not implemented", 0); - CHECK(arg_0->lit.as_u64[0] == 0, "Not implemented", 0); - CHECK(arg_1->lit.as_u64[0] == 0, "Not implemented", 0); - CHECK(arg_2->lit.as_u64[0] == 0, "Not implemented", 0); + CHECK(arg_0->op == DATA_PTR, "Not implemented",); + CHECK(arg_1->op == DATA_PTR, "Not implemented",); + CHECK(arg_2->op == DATA_PTR, "Not implemented",); + CHECK(arg_0->lit.as_u64[0] == 0, "Not implemented",); + CHECK(arg_1->lit.as_u64[0] == 0, "Not implemented",); + CHECK(arg_2->lit.as_u64[0] == 0, "Not implemented",); write_u8(LE, 0x31, begin, end); // xor edx write_u8(LE, 0xd2, begin + 1, end); // edx @@ -1991,7 +2682,7 @@ void x86_64_emit_node( write_u8(LE, 0x48, begin + 6, end); // movabs write_u8(LE, 0xb8, begin + 7, end); // rax - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_PROC_ADDRESS, .offset = codegen->offset_code + 8, .size = 8, @@ -2031,29 +2722,29 @@ void x86_64_emit_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->op == DATA_REFERENCE, "Not implemented",); + CHECK(arg_1->op == DATA_I32, "Not implemented",); + CHECK(arg_2->op == DATA_REFERENCE, "Not implemented",); + CHECK(arg_3->op == DATA_PTR, "Not implemented",); + CHECK(arg_4->op == DATA_PTR, "Not implemented",); + CHECK(arg_5->op == DATA_PTR, "Not implemented",); + CHECK(arg_6->op == DATA_PTR, "Not implemented",); - 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(arg_0->ref != UNDEFINED, "Internal",); + CHECK(pool->entities[arg_0->ref].is_enabled, "Internal",); + CHECK(arg_2->ref != UNDEFINED, "Internal",); + CHECK(pool->entities[arg_2->ref].is_enabled, "Internal",); - CHECK(pool->entities[arg_0->ref].type == ENTITY_PROC, "Not implemented", 0); - CHECK(pool->entities[arg_2->ref].type == ENTITY_NODE, "Not implemented", 0); + CHECK(pool->entities[arg_0->ref].type == ENTITY_PROC, "Not implemented",); + CHECK(pool->entities[arg_2->ref].type == ENTITY_NODE, "Not implemented",); // Write data // Node *dat_2 = &pool->entities[arg_2->ref].node; - CHECK(dat_2->op == DATA_PTR, "Not implemented", 0); + CHECK(dat_2->op == DATA_PTR, "Not implemented",); - CHECK(codegen->offset_ro_data + dat_2->lit.num_bytes <= codegen->max_ro_data_size, "Out of memory", 0); + CHECK(codegen->offset_ro_data + dat_2->lit.num_bytes <= codegen->max_ro_data_size, "Out of memory",); i64 arg_2_offset = codegen->offset_ro_data; mem_cpy(codegen->buffer_ro_data + arg_2_offset, dat_2->lit.as_u8, dat_2->lit.num_bytes); @@ -2064,7 +2755,7 @@ void x86_64_emit_node( write_u8 (LE, 0x48, begin, end); // movabs write_u8 (LE, 0xbf, begin + 1, end); // rdi - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_PROC_ADDRESS, .offset = codegen->offset_code + 2, .size = 8, @@ -2076,7 +2767,7 @@ void x86_64_emit_node( write_u8 (LE, 0x48, begin + 15, end); // movabs write_u8 (LE, 0xba, begin + 16, end); // rdx - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_RO_DATA_ADDRESS, .offset = codegen->offset_code + 17, .size = 8, @@ -2108,7 +2799,7 @@ void x86_64_emit_node( write_u8 (LE, 0x48, begin + 70, end); // movabs write_u8 (LE, 0xb8, begin + 71, end); // rax - codegen->rels[codegen->num_rels++] = (Rel_Entry) { + codegen->rels[codegen->num_rels++] = (Codegen_Rel_Entry) { .type = REL_ADD_PROC_ADDRESS, .offset = codegen->offset_code + 72, .size = 8, @@ -2152,15 +2843,15 @@ void x86_64_emit_node( LOG(WARNING, "Some return values are ignored for node %lld", 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); + CHECK(n_val != UNDEFINED, "Internal",); + CHECK(pool->entities[n_val].is_enabled, "Internal",); + CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal",); Node *val = &pool->entities[n_val].node; switch (val->op) { case DATA_I64: { - CHECK(val->lit.num_bytes == 8, "Not implemented", 0); + CHECK(val->lit.num_bytes == 8, "Not implemented",); write_u8 (LE, 0xb8, begin, end); // mov eax write_u32(LE, 60, begin + 1, end); // 60 @@ -2175,6 +2866,45 @@ void x86_64_emit_node( } break; case DATA_ADD: { + switch (codegen->entities[n_val].reg) { + case 1: + // eax + break; + + case 2: + // ebx + + write_u8 (LE, 0x89, begin, end); // mov eax + write_u8 (LE, 0xd8, begin + 1, end); // ebx + + begin += 2; + codegen->offset_code += 2; + break; + + case 3: + // ecx + + write_u8 (LE, 0x89, begin, end); // mov eax + write_u8 (LE, 0xc8, begin + 1, end); // ecx + + begin += 2; + codegen->offset_code += 2; + break; + + case 4: + // edx + + write_u8 (LE, 0x89, begin, end); // mov eax + write_u8 (LE, 0xd0, begin + 1, end); // edx + + begin += 2; + codegen->offset_code += 2; + break; + + default: + FAIL("Not implemented",); + } + write_u8 (LE, 0x89, begin, end); // mov edi write_u32(LE, 0xc7, begin + 1, end); // eax @@ -2192,18 +2922,18 @@ void x86_64_emit_node( } } } else { - CHECK(n->ret.num_vals == 1, "Not implemented", 0); + CHECK(n->ret.num_vals == 1, "Not implemented",); 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); + CHECK(n_val != UNDEFINED, "Internal",); + CHECK(pool->entities[n_val].is_enabled, "Internal",); + CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal",); Node *val = &pool->entities[n_val].node; switch (val->op) { case DATA_I32: { - CHECK(val->lit.num_bytes == 4, "Not implemented", 0); + CHECK(val->lit.num_bytes == 4, "Not implemented",); write_u8 (LE, 0xb8, begin, end); // mov eax write_u32(LE, val->lit.as_u32[0], begin + 1, end); @@ -2213,7 +2943,9 @@ void x86_64_emit_node( } break; case DATA_ADD: { - write_u8(LE, 0xc3, begin + 5, end); // ret + CHECK(codegen->entities[n_val].reg == 1, "Not implemented",); + + write_u8(LE, 0xc3, begin, end); // ret codegen->offset_code += 1; } break; @@ -2238,16 +2970,16 @@ void emit_proc( u16 arch, u32 context ) { - CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0); - CHECK(proc != UNDEFINED && pool->entities[proc].is_enabled, "No proc", 0); - CHECK(pool->entities[proc].type == ENTITY_PROC, "Invalid entity", 0); - CHECK(arch == ARCH_X86_64, "Target not supported", 0); + CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments",); + CHECK(proc != UNDEFINED && pool->entities[proc].is_enabled, "No proc",); + CHECK(pool->entities[proc].type == ENTITY_PROC, "Invalid entity",); + CHECK(arch == ARCH_X86_64, "Target not supported",); Proc *p = &pool->entities[proc].proc; - CHECK(p->codegen.emit_done == 0, "Emit already done", 0); + CHECK(codegen->entities[proc].emit_done == 0, "Emit already done",); - p->codegen.offset = codegen->offset_code; + codegen->entities[proc].offset = codegen->offset_code; // TODO Sort nodes in the sequential execution order. // @@ -2255,15 +2987,15 @@ void emit_proc( // Now we assume that nodes are already sorted. for (i64 i = 0; i < p->num_nodes; ++i) - x86_64_emit_node(pool, codegen, p->nodes[i], context); + x86_64_emit_node(pool, codegen, codegen->entities + proc, p->nodes[i], context); - p->codegen.emit_done = 1; + codegen->entities[proc].emit_done = 1; } void emit_unit(Pool *pool, Codegen_Context *codegen, i64 unit, u16 arch) { - CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0); - CHECK(unit != UNDEFINED && pool->entities[unit].is_enabled, "No unit", 0); - CHECK(pool->entities[unit].type == ENTITY_UNIT, "Invalid entity", 0); + CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments",); + CHECK(unit != UNDEFINED && pool->entities[unit].is_enabled, "No unit",); + CHECK(pool->entities[unit].type == ENTITY_UNIT, "Invalid entity",); for (i64 i = 0; i < pool->entities[unit].unit.num_procs; ++i) { u32 context = 0; @@ -2650,13 +3382,13 @@ i64 unit_write_in_memory( u16 format, u16 arch ) { - CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments",); - CHECK(unit != UNDEFINED && pool->entities[unit].is_enabled, "No unit",); - CHECK(pool->entities[unit].type == ENTITY_UNIT, "Invalid entity", 0); - CHECK(format == FORMAT_ELF && arch == ARCH_X86_64, "Target not supported",); - CHECK(linker->obj_file_buffer != NULL, "No object file buffer",); - CHECK(linker->dependencies_buffer != NULL, "No dependencies buffer",); - CHECK(linker->obj_file_offsets != NULL, "No object file offsets buffer",); + CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments", 0); + CHECK(unit != UNDEFINED && pool->entities[unit].is_enabled, "No unit", 0); + CHECK(pool->entities[unit].type == ENTITY_UNIT, "Invalid entity", 0); + CHECK(format == FORMAT_ELF && arch == ARCH_X86_64, "Target not supported", 0); + CHECK(linker->obj_file_buffer != NULL, "No object file buffer", 0); + CHECK(linker->dependencies_buffer != NULL, "No dependencies buffer", 0); + CHECK(linker->obj_file_offsets != NULL, "No object file offsets buffer", 0); emit_unit(pool, codegen, unit, arch); @@ -2690,7 +3422,7 @@ i64 unit_write_in_memory( Offset_Num headers = elf_section_headers(buf); for (i64 sec_index = 1; sec_index < headers.num; ++sec_index, ++num_sections_total) { - CHECK(num_sections_total < linker->max_num_sections, "Too many sections",); + CHECK(num_sections_total < linker->max_num_sections, "Too many sections", 0); Elf_Section_Header section = elf_section(buf, sec_index); c8 * name = elf_name_from_offset(buf, section.name); @@ -2779,8 +3511,8 @@ i64 unit_write_in_memory( Elf_Relx_Entry relx = elf_relx(buf, symtab, strtab, src_sec.data, entry_index, src_sec.type == SEC_RELA); c8 * sym_name = elf_name_from_offset(buf, relx.symbol.name); - CHECK(relx.symbol.section != 65521, "Sanity",); - CHECK(relx.symbol.section != 65522, "Sanity",); + CHECK(relx.symbol.section != 65521, "Sanity", 0); + CHECK(relx.symbol.section != 65522, "Sanity", 0); switch (relx.type) { case R_X86_64_GOT32: @@ -2808,7 +3540,7 @@ i64 unit_write_in_memory( if (found) break; - CHECK(num_symbols < linker->max_num_symbols, "Out of memory",); + CHECK(num_symbols < linker->max_num_symbols, "Out of memory", 0); linker->symbols[num_symbols++] = (Link_Sym_Entry) { .name_size = relx.symbol.name.size, .name = sym_name, @@ -2855,7 +3587,7 @@ i64 unit_write_in_memory( Offset_Num headers = elf_section_headers(buf); for (i64 sec_index = 1; sec_index < headers.num; ++sec_index, ++sec_index_global) { - CHECK(sec_index_global < num_sections_total, "Buffer overflow",); + CHECK(sec_index_global < num_sections_total, "Buffer overflow", 0); Elf_Section_Header section = elf_section(buf, sec_index); c8 * name = elf_name_from_offset(buf, section.name); @@ -2936,7 +3668,7 @@ i64 unit_write_in_memory( c8 * sym_name = elf_name_from_offset(buf, sym.name); if (sym.type == SYM_TLS && sym.section != 0) - CHECK(elf_section(buf, sym.section).tls, "Sanity",); + CHECK(elf_section(buf, sym.section).tls, "Sanity", 0); if (sym.section == 0) // undefined symbol continue; @@ -2949,12 +3681,12 @@ i64 unit_write_in_memory( if (sym.section != 65521 && elf_section(buf, sym.section).alloc) { i64 sym_section = sec_index_global + sym.section - 1; - CHECK(sym_section < num_sections_total, "Buffer overflow",); - CHECK(linker->sections[sym_section].address != 0, "Sanity",); + CHECK(sym_section < num_sections_total, "Buffer overflow", 0); + CHECK(linker->sections[sym_section].address != 0, "Sanity", 0); sym_address += linker->sections[sym_section].address; } - CHECK(num_symbols < linker->max_num_symbols, "Too many symbols",); + CHECK(num_symbols < linker->max_num_symbols, "Too many symbols", 0); linker->symbols[num_symbols++] = (Link_Sym_Entry) { .name_size = sym.name.size, @@ -2982,26 +3714,7 @@ i64 unit_write_in_memory( // // Add runtime library symbols - #define ADD_UNIQUE_(i_, name_, ...) \ - do { \ - b8 found_ = 0; \ - for (i_ = 0; i_ < num_symbols; ++i_) \ - if (STR_EQ(linker->symbols[i_].name_size, \ - linker->symbols[i_].name, \ - name_)) { \ - found_ = 1; \ - break; \ - } \ - CHECK(!found_, "Forbidden symbol: " name_,); \ - CHECK(num_symbols < linker->max_num_symbols, "Too many symbols",); \ - linker->symbols[num_symbols++] = (Link_Sym_Entry) { \ - .name_size = sizeof name_ - 1, \ - .name = name_, \ - __VA_ARGS__ \ - }; \ - } while (0) - - #define ADD_IF_MISSING_(name_, ...) \ + #define ADD_UNIQUE_(i_, name_, ...) \ do { \ b8 found_ = 0; \ for (i_ = 0; i_ < num_symbols; ++i_) \ @@ -3011,14 +3724,33 @@ i64 unit_write_in_memory( found_ = 1; \ break; \ } \ - if (!found_) { \ - CHECK(num_symbols < linker->max_num_symbols, "Too many symbols",); \ - linker->symbols[num_symbols++] = (Link_Sym_Entry) { \ - .name_size = sizeof name_ - 1, \ - .name = name_, \ - __VA_ARGS__ \ - }; \ - } \ + CHECK(!found_, "Forbidden symbol: " name_, 0); \ + CHECK(num_symbols < linker->max_num_symbols, "Too many symbols", 0); \ + linker->symbols[num_symbols++] = (Link_Sym_Entry) { \ + .name_size = sizeof name_ - 1, \ + .name = name_, \ + __VA_ARGS__ \ + }; \ + } while (0) + + #define ADD_IF_MISSING_(name_, ...) \ + do { \ + b8 found_ = 0; \ + for (i_ = 0; i_ < num_symbols; ++i_) \ + if (STR_EQ(linker->symbols[i_].name_size, \ + linker->symbols[i_].name, \ + name_)) { \ + found_ = 1; \ + break; \ + } \ + if (!found_) { \ + CHECK(num_symbols < linker->max_num_symbols, "Too many symbols", 0); \ + linker->symbols[num_symbols++] = (Link_Sym_Entry) { \ + .name_size = sizeof name_ - 1, \ + .name = name_, \ + __VA_ARGS__ \ + }; \ + } \ } while (0) // ---------------------------------------------------------- @@ -3106,17 +3838,17 @@ i64 unit_write_in_memory( i64 dst_index = elf_find_related_section_index(buf, sec_index); i64 dst_index_global = sec_index_global + dst_index - 1; - CHECK(dst_index_global >= 0 && dst_index_global < linker->max_num_sections, "Buffer overflow",); + CHECK(dst_index_global >= 0 && dst_index_global < linker->max_num_sections, "Buffer overflow", 0); for (i64 entry_index = 0; entry_index < src_sec.num_entries; ++entry_index, ++rel_index_global) { Elf_Relx_Entry relx = elf_relx(buf, symtab, strtab, src_sec.data, entry_index, src_sec.type == SEC_RELA); c8 * sym_name = elf_name_from_offset(buf, relx.symbol.name); i64 sym_index_global = num_symbols; - CHECK(relx.symbol.section != 65521, "Sanity",); - CHECK(relx.symbol.section != 65522, "Sanity",); + CHECK(relx.symbol.section != 65521, "Sanity", 0); + CHECK(relx.symbol.section != 65522, "Sanity", 0); - CHECK(num_symbols < linker->max_num_symbols, "Out of memory",); + CHECK(num_symbols < linker->max_num_symbols, "Out of memory", 0); if (relx.symbol.section == 0) { b8 found = 0; @@ -3127,10 +3859,10 @@ i64 unit_write_in_memory( str_eq(pool->entities[i].proc.name_size, pool->entities[i].proc.name, relx.symbol.name.size, sym_name)) { - CHECK(pool->entities[i].proc.codegen.emit_done, "No proc code",); + CHECK(codegen->entities[i].emit_done, "No proc code", 0); linker->symbols[num_symbols++] = (Link_Sym_Entry) { - .address = rx_code_address + pool->entities[i].proc.codegen.offset, + .address = rx_code_address + codegen->entities[i].offset, .size = relx.symbol.value.size, }; @@ -3174,8 +3906,8 @@ i64 unit_write_in_memory( if (sym_index_global >= num_symbols) LOG(ERROR, "Symbol: %s", sym_name); - CHECK(sym_index_global < num_symbols, "Symbol not found",); - CHECK(rel_index_global < linker->max_num_rels, "Out of memory",); + CHECK(sym_index_global < num_symbols, "Symbol not found", 0); + CHECK(rel_index_global < linker->max_num_rels, "Out of memory", 0); linker->rels[rel_index_global].symbol = sym_index_global; @@ -3187,7 +3919,7 @@ i64 unit_write_in_memory( if (!STR_EQ(relx.symbol.name.size, sym_name, "_DYNAMIC") && linker->symbols[sym_index_global].got_offset == 0) { got_offset += ELF_GOT_ENTRY_SIZE; - CHECK(got_offset < rw_got_size, "Sanity",); + CHECK(got_offset < rw_got_size, "Sanity", 0); linker->symbols[sym_index_global].got_offset = got_offset; } break; @@ -3218,7 +3950,7 @@ i64 unit_write_in_memory( i64 dst_index = elf_find_related_section_index(buf, sec_index); i64 dst_index_global = sec_index_global + dst_index - 1; - CHECK(dst_index_global >= 0 && dst_index_global < linker->max_num_sections, "Buffer overflow",); + CHECK(dst_index_global >= 0 && dst_index_global < linker->max_num_sections, "Buffer overflow", 0); for (i64 entry_index = 0; entry_index < src_sec.num_entries; ++entry_index, ++rel_index_global) { Elf_Relx_Entry relx = elf_relx(buf, symtab, strtab, src_sec.data, entry_index, src_sec.type == SEC_RELA); @@ -3386,7 +4118,7 @@ i64 unit_write_in_memory( #undef FIND_ for (i64 rel_index = 0; rel_index < codegen->num_rels; ++rel_index) { - Rel_Entry rel = codegen->rels[rel_index]; + Codegen_Rel_Entry rel = codegen->rels[rel_index]; u8 *begin = codegen->buffer_code + rel.offset; u8 *end = codegen->buffer_code + codegen->offset_code; @@ -3427,10 +4159,9 @@ i64 unit_write_in_memory( } 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); + CHECK(codegen->entities[rel.proc].emit_done, "No proc address", 0); - i64 value = rel.value + rx_code_address + p->codegen.offset; + i64 value = rel.value + rx_code_address + codegen->entities[rel.proc].offset; write_i64(LE, value, begin, end); found = 1; @@ -3451,7 +4182,7 @@ i64 unit_write_in_memory( // i64 output_size = align(rw_tls_data_offset + rw_tls_data_size, X86_64_PAGE_SIZE); - CHECK(output_size <= linker->max_output_size, "Out of memory",); + CHECK(output_size <= linker->max_output_size, "Out of memory", 0); i64 entry = rx_code_address + codegen->entry_point; @@ -3467,7 +4198,7 @@ i64 unit_write_in_memory( break; } - CHECK(found, "Undefined symbol: _start",); + CHECK(found, "Undefined symbol: _start", 0); } LOG(VERBOSE, "Entry point: 0x%llx", entry); @@ -3519,12 +4250,12 @@ i64 unit_write_in_memory( // Program headers // - CHECK(rx_code_offset % X86_64_PAGE_SIZE == rx_code_address % X86_64_PAGE_SIZE, "Invalid alignment",); - CHECK(rw_data_offset % X86_64_PAGE_SIZE == rw_data_address % X86_64_PAGE_SIZE, "Invalid alignment",); - CHECK(ro_data_offset % X86_64_PAGE_SIZE == ro_data_address % X86_64_PAGE_SIZE, "Invalid alignment",); - CHECK(rw_got_offset % X86_64_PAGE_SIZE == rw_got_address % X86_64_PAGE_SIZE, "Invalid alignemtn",); - CHECK(rw_dynamic_offset % X86_64_PAGE_SIZE == rw_dynamic_address % X86_64_PAGE_SIZE, "Invalid alignemtn",); - CHECK(rw_tls_data_offset % X86_64_PAGE_SIZE == rw_tls_data_address % X86_64_PAGE_SIZE, "Invalid alignment",); + CHECK(rx_code_offset % X86_64_PAGE_SIZE == rx_code_address % X86_64_PAGE_SIZE, "Invalid alignment", 0); + CHECK(rw_data_offset % X86_64_PAGE_SIZE == rw_data_address % X86_64_PAGE_SIZE, "Invalid alignment", 0); + CHECK(ro_data_offset % X86_64_PAGE_SIZE == ro_data_address % X86_64_PAGE_SIZE, "Invalid alignment", 0); + CHECK(rw_got_offset % X86_64_PAGE_SIZE == rw_got_address % X86_64_PAGE_SIZE, "Invalid alignemtn", 0); + CHECK(rw_dynamic_offset % X86_64_PAGE_SIZE == rw_dynamic_address % X86_64_PAGE_SIZE, "Invalid alignemtn", 0); + CHECK(rw_tls_data_offset % X86_64_PAGE_SIZE == rw_tls_data_address % X86_64_PAGE_SIZE, "Invalid alignment", 0); u8 *h = o + ELF_HEADER_SIZE; @@ -3644,8 +4375,8 @@ i64 unit_write_in_memory( write_u16(LE, num_program_headers, o + 56, o_end); - CHECK(h == o + ELF_HEADER_SIZE + num_program_headers * ELF_PROGRAM_HEADER_SIZE, "Invalid num program headers",); - CHECK(rx_code_offset >= h - o, "Sanity",); + CHECK(h == o + ELF_HEADER_SIZE + num_program_headers * ELF_PROGRAM_HEADER_SIZE, "Invalid num program headers", 0); + CHECK(rx_code_offset >= h - o, "Sanity", 0); // Code // @@ -3669,8 +4400,8 @@ i64 unit_write_in_memory( section.data.size == 0) continue; u8 *p = o + offset; - CHECK(p >= o + program_offset + codegen->offset_code, "Buffer overflow",); - CHECK(p + section.data.size <= o + output_size, "Buffer overflow",); + CHECK(p >= o + program_offset + codegen->offset_code, "Buffer overflow", 0); + CHECK(p + section.data.size <= o + output_size, "Buffer overflow", 0); mem_cpy(p, buf.begin + section.data.offset, section.data.size); } } @@ -3685,7 +4416,7 @@ i64 unit_write_in_memory( continue; offset += ELF_GOT_ENTRY_SIZE; - CHECK(offset < rw_got_size, "Sanity",); + CHECK(offset < rw_got_size, "Sanity", 0); write_u64(LE, sym->address, o + rw_got_offset + offset, o_end); } @@ -3704,6 +4435,8 @@ void unit_write( i64 io_out, void * io_user_data ) { + CHECK(unit != UNDEFINED, "Invalid unit",); + // ============================================================== // // Reading dependencies @@ -3825,6 +4558,7 @@ void unit_write( codegen->offset_ro_data = 0; linker->num_obj_files = 0; + mem_set(codegen->entities, 0, MAX_NUM_ENTITIES * sizeof *codegen->entities); mem_set(codegen->rels, 0, codegen->max_num_rels * sizeof *codegen->rels); mem_set(codegen->buffer_code, 0, codegen->max_code_size); mem_set(codegen->buffer_ro_data, 0, codegen->max_ro_data_size); @@ -4093,7 +4827,8 @@ Codegen_Context g_codegen = { .offset_code = 0, .offset_ro_data = 0, - .rels = (Rel_Entry[MAX_NUM_RELS]) {0}, + .entities = (Codegen_Entity[MAX_NUM_ENTITIES]) {0}, + .rels = (Codegen_Rel_Entry[MAX_NUM_RELS]) {0}, .buffer_code = (u8[MAX_CODE_SIZE]) {0}, .buffer_ro_data = (u8[MAX_CODE_SIZE]) {0}, }; @@ -4310,14 +5045,42 @@ c8 *l_find(c8 *name, b8 silent) { #if HELPERS -b8 link_with_libc(void) { - // ============================================================ - // - // Create the program semantic tree - - // Add a compilation unit. - i64 u = u_new(); +#define ADD_TEST_(name_, res_, ...) \ + b8 name_(void) { \ + i64 u = u_new(); \ + CHECK(u != UNDEFINED, "Sanity", 0); \ + \ + __VA_ARGS__ \ + \ + u_elf_x86_64(u, "test_" #name_); \ + \ + b8 success = 1; \ + \ + if (HOST_OS != OS_Linux) { \ + LOG(INFO, "Skip running the executable. Host system is not compatible."); \ + } else if (HO != LE) { \ + LOG(INFO, "Skip running the executable. Host data ordering is not compatible."); \ + } else { \ + LOG(VERBOSE, "Running the executable"); \ + \ + i32 ret; \ + \ + if (LOG_LEVEL >= VERBOSE) \ + ret = system("./test_" #name_); \ + else \ + ret = system("./test_" #name_ " >/dev/null"); \ + \ + if (WEXITSTATUS(ret) != res_) \ + success = 0; \ + } \ + \ + if (success) \ + system("rm test_" #name_); \ + \ + return success; \ + } +ADD_TEST_(link_with_libc, 42, // Add the main proc. i64 mainproc = p_new(u, "main"); { @@ -4335,12 +5098,6 @@ b8 link_with_libc(void) { ); } - // ============================================================ - // - // Compile and link - // - // TODO - // Add dependencies if (l_find("c_nonshared", 1)[0] != '\0') @@ -4348,113 +5105,126 @@ b8 link_with_libc(void) { else l_static(u, "c"); l_object(u, "crt1"); +) - // l_object(u, "crti"); - // l_object(u, "crtn"); - - // Write the compilation unit into an executable file. - u_elf_x86_64(u, "test_foo"); - - // ============================================================ - - b8 success = 1; - - if (HOST_OS != OS_Linux) { - LOG(INFO, "Skip running the executable. Host system is not compatible."); - } else if (HO != LE) { - LOG(INFO, "Skip running the executable. Host data ordering is not compatible."); - } else { - LOG(VERBOSE, "Running the executable"); - - i32 ret; - - if (LOG_LEVEL >= VERBOSE) - ret = system("./test_foo"); - else - ret = system("./test_foo >/dev/null"); - - if (WEXITSTATUS(ret) != 42) - success = 0; - } - - system("rm test_foo"); - - return success; -} +ADD_TEST_(math_two_plus_two, 4, + i64 mainproc = p_new_entry(u); -b8 two_plus_two(void) { - i64 u = u_new(); + N_RET( + mainproc, + n_add(mainproc, n_i32(mainproc, 2), n_i32(mainproc, 2)) + ); +) +ADD_TEST_(math_sixty_nine, 69, i64 mainproc = p_new_entry(u); N_RET( mainproc, - n_add(mainproc, n_i32(mainproc, 2), n_i32(mainproc, 2)) + n_add(mainproc, n_i32(mainproc, 27), n_i32(mainproc, 42)) ); +) - u_elf_x86_64(u, "test_two_plus_two"); +ADD_TEST_(math_add_3, 1+2+3, + i64 mainproc = p_new_entry(u); - b8 success = 1; + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_i32(mainproc, 3); - if (HOST_OS != OS_Linux) { - LOG(INFO, "Skip running the executable. Host system is not compatible."); - } else if (HO != LE) { - LOG(INFO, "Skip running the executable. Host data ordering is not compatible."); - } else { - LOG(VERBOSE, "Running the executable"); + N_RET( + mainproc, + n_add(mainproc, a, b) + ); +) - i32 ret; +ADD_TEST_(math_add_4a, 1+2+3+4, + i64 mainproc = p_new_entry(u); - if (LOG_LEVEL >= VERBOSE) - ret = system("./test_two_plus_two"); - else - ret = system("./test_two_plus_two >/dev/null"); + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_add(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 4)); - if (WEXITSTATUS(ret) != 4) - success = 0; - } + N_RET( + mainproc, + n_add(mainproc, a, b) + ); +) - system("rm test_two_plus_two"); +ADD_TEST_(math_add_5, 1+2+3+4+5, + i64 mainproc = p_new_entry(u); - return success; -} + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_add(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 4)); + i64 c = n_i32(mainproc, 5); + i64 a_b = n_add(mainproc, a, b); -b8 sixty_nine(void) { - i64 u = u_new(); + N_RET( + mainproc, + n_add(mainproc, a_b, c) + ); +) +ADD_TEST_(math_add_6, 1+2+3+4+5+6, i64 mainproc = p_new_entry(u); + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_add(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 4)); + i64 c = n_add(mainproc, n_i32(mainproc, 5), n_i32(mainproc, 6)); + i64 a_b = n_add(mainproc, a, b); + N_RET( mainproc, - n_add(mainproc, n_i32(mainproc, 27), n_i32(mainproc, 42)) + n_add(mainproc, a_b, c) ); +) - u_elf_x86_64(u, "test_sixty_nine"); +ADD_TEST_(math_add_7, 1+2+3+4+5+6+7, + i64 mainproc = p_new_entry(u); - b8 success = 1; + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_add(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 4)); + i64 c = n_add(mainproc, n_i32(mainproc, 5), n_i32(mainproc, 6)); + i64 d = n_i32(mainproc, 7); + i64 a_b = n_add(mainproc, a, b); + i64 c_d = n_add(mainproc, c, d); - if (HOST_OS != OS_Linux) { - LOG(INFO, "Skip running the executable. Host system is not compatible."); - } else if (HO != LE) { - LOG(INFO, "Skip running the executable. Host data ordering is not compatible."); - } else { - LOG(VERBOSE, "Running the executable"); + N_RET( + mainproc, + n_add(mainproc, a_b, c_d) + ); +) - i32 ret; +ADD_TEST_(math_add_4b, 5+6+7+8, + i64 mainproc = p_new_entry(u); - if (LOG_LEVEL >= VERBOSE) - ret = system("./test_sixty_nine"); - else - ret = system("./test_sixty_nine >/dev/null"); + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_add(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 4)); + i64 c = n_add(mainproc, n_i32(mainproc, 5), n_i32(mainproc, 6)); + i64 d = n_add(mainproc, n_i32(mainproc, 7), n_i32(mainproc, 8)); + i64 a_b = n_add(mainproc, a, b); + i64 c_d = n_add(mainproc, c, d); + (void) a_b; - if (WEXITSTATUS(ret) != 69) - success = 0; - } + N_RET( + mainproc, + c_d + ); +) - system("rm test_sixty_nine"); +ADD_TEST_(math_add_8, 1+2+3+4+5+6+7+8, + i64 mainproc = p_new_entry(u); - return success; -} + i64 a = n_add(mainproc, n_i32(mainproc, 1), n_i32(mainproc, 2)); + i64 b = n_add(mainproc, n_i32(mainproc, 3), n_i32(mainproc, 4)); + i64 c = n_add(mainproc, n_i32(mainproc, 5), n_i32(mainproc, 6)); + i64 d = n_add(mainproc, n_i32(mainproc, 7), n_i32(mainproc, 8)); + i64 a_b = n_add(mainproc, a, b); + i64 c_d = n_add(mainproc, c, d); + + N_RET( + mainproc, + n_add(mainproc, a_b, c_d) + ); +) #endif // HELPERS @@ -4524,8 +5294,15 @@ i32 main(i32 argc, c8 **argv) { #if HELPERS // RUN_TEST_(link_with_libc); - RUN_TEST_(two_plus_two); - RUN_TEST_(sixty_nine); + RUN_TEST_(math_two_plus_two); + RUN_TEST_(math_sixty_nine); + RUN_TEST_(math_add_3); + RUN_TEST_(math_add_4a); + RUN_TEST_(math_add_5); + RUN_TEST_(math_add_6); + RUN_TEST_(math_add_7); + RUN_TEST_(math_add_4b); + RUN_TEST_(math_add_8); #endif #undef RUN_TEST_ |