diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-16 05:12:21 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-16 05:12:21 +0100 |
commit | 896066dfbf1a5cbfd235565d1f770ee5eac9930d (patch) | |
tree | 42d7ff93505f2446385e8cef511361ab865ce6fa | |
parent | 8c99b5df10b644de003b6e26e270272504200df9 (diff) | |
download | bxgen-896066dfbf1a5cbfd235565d1f770ee5eac9930d.zip |
two plus two test
-rwxr-xr-x | bxgen.c | 393 |
1 files changed, 255 insertions, 138 deletions
@@ -109,17 +109,17 @@ #/ SRC=${0##*./} BIN=${SRC%.*} -gcc \ - -Wall -Wextra -Werror -pedantic \ - -Wno-old-style-declaration \ - -Wno-missing-braces \ - -Wno-unused-variable \ - -Wno-unused-but-set-variable \ - -Wno-unused-parameter \ - -O0 \ - -fsanitize=undefined,address,leak -mshstk \ - -o $BIN $SRC && \ - ./$BIN $@ && \ +gcc \ + -Wall -Wextra -Werror -pedantic \ + -Wno-old-style-declaration \ + -Wno-missing-braces \ + -Wno-unused-variable \ + -Wno-unused-but-set-variable \ + -Wno-unused-parameter \ + -O0 \ + -fsanitize=undefined,address,leak \ + -o $BIN $SRC && \ + ./$BIN $@ && \ rm $BIN exit $? # */ #endif @@ -232,6 +232,7 @@ enum { DATA_I64, DATA_F32, DATA_F64, + DATA_ADD, DATA_REFERENCE, CTRL_CALL, CTRL_RET, @@ -364,6 +365,7 @@ typedef struct { Var ref; Ret ret; Call call; + Var add[2]; }; } Node; @@ -532,6 +534,7 @@ 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_data_add(Pool *pool, Var x, Var y); 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); @@ -575,6 +578,7 @@ i64 n_i32(i64 proc, i32 value); i64 n_i64(i64 proc, i64 value); 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_add(i64 proc, Var x, Var y); i64 n_ret(i64 proc, i64 num_vals, Var *vals); i64 p_new(i64 unit, c8 *name); @@ -870,6 +874,16 @@ i64 node_data_i64(Pool *pool, i64 value) { }); } +i64 node_data_add(Pool *pool, Var x, Var y) { + return node_init(pool, (Node) { + .op = DATA_ADD, + .add = { + x, + y, + }, + }); +} + u16 resolve_calling_convention(Pool *pool, i64 proc) { CHECK(pool != NULL, "Invalid arguments",); CHECK(proc != UNDEFINED, "Invalid arguments",); @@ -1521,25 +1535,25 @@ void write_f64(u32 ordering, f64 x, void *v, void *v_end) { // ================================================================ enum { - HOST_Unknown = 0, - HOST_Unix, - HOST_Linux, - HOST_Windows, - HOST_macOS, - HOST_Cygwin, + OS_Unknown = 0, + OS_Unix, + OS_Linux, + OS_Windows, + OS_macOS, + OS_Cygwin, #if defined(__CYGWIN__) - HOST = HOST_Cygwin, + HOST_OS = OS_Cygwin, #elif defined(_WIN32) - HOST = HOST_Windows, + HOST_OS = OS_Windows, #elif defined(__linux__) - HOST = HOST_Linux, + HOST_OS = OS_Linux, #elif defined(__APPLE__) - HOST = HOST_macOS, + HOST_OS = OS_macOS, #elif defined(__unix__) - HOST = HOST_Unix, + HOST_OS = OS_Unix, #else - HOST = HOST_Unknown, + HOST_OS = OS_Unknown, #endif // x86_64 constants @@ -1825,6 +1839,30 @@ void x86_64_emit_node( // Do nothing break; + case DATA_ADD: + 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",); + } + + 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",); + } + + codegen->offset_code += 10; + break; + case CTRL_CALL: { CHECK(n->call.convention == CONV_CDECL, "Not implemented", 0); CHECK(n->call.target_proc == UNDEFINED, "Not implemented", 0); @@ -2081,13 +2119,17 @@ void x86_64_emit_node( case CTRL_RET: { if ((context & EMIT_ENTRY_PROC) != 0) { - write_u8 (LE, 0xb8, begin, end); // mov eax - write_u32(LE, 60, begin + 1, end); // 60 - if (n->ret.num_vals == 0) { + write_u8 (LE, 0xb8, begin, end); // mov eax + write_u32(LE, 60, begin + 1, end); // 60 + write_u8 (LE, 0xbf, begin + 5, end); // mov edi write_u32(LE, 0, begin + 6, end); // 0 + write_u8 (LE, 0x0f, begin + 10, end); // syscall + write_u8 (LE, 0x05, begin + 11, end); + + codegen->offset_code += 12; } else { if (n->ret.num_vals > 1) LOG(WARNING, "Some return values are ignored for node %lld", node); @@ -2098,17 +2140,40 @@ void x86_64_emit_node( CHECK(pool->entities[n_val].type == ENTITY_NODE, "Internal", 0); Node *val = &pool->entities[n_val].node; - CHECK(val->op == DATA_I64, "Not implemented", 0); - CHECK(val->lit.num_bytes == 8, "Not implemented", 0); - write_u8 (LE, 0xbf, begin + 5, end); // mov edi - write_u32(LE, *val->lit.as_u32, begin + 6, end); // <- literal - } + switch (val->op) { + case DATA_I64: { + CHECK(val->lit.num_bytes == 8, "Not implemented", 0); + + write_u8 (LE, 0xb8, begin, end); // mov eax + write_u32(LE, 60, begin + 1, end); // 60 + + write_u8 (LE, 0xbf, begin + 5, end); // mov edi + write_u32(LE, *val->lit.as_u32, begin + 6, end); // <- literal + + write_u8 (LE, 0x0f, begin + 10, end); // syscall + write_u8 (LE, 0x05, begin + 11, end); + + codegen->offset_code += 12; + } break; + + case DATA_ADD: { + write_u8 (LE, 0x89, begin, end); // mov edi + write_u32(LE, 0xc7, begin + 1, end); // eax - write_u8 (LE, 0x0f, begin + 10, end); // syscall - write_u8 (LE, 0x05, begin + 11, end); + write_u8 (LE, 0xb8, begin + 2, end); // mov eax + write_u32(LE, 60, begin + 3, end); // 60 - codegen->offset_code += 12; + write_u8 (LE, 0x0f, begin + 7, end); // syscall + write_u8 (LE, 0x05, begin + 8, end); + + codegen->offset_code += 9; + } break; + + default: + FAIL("Not implemented",); + } + } } else { CHECK(n->ret.num_vals == 1, "Not implemented", 0); @@ -2118,14 +2183,27 @@ void x86_64_emit_node( 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 + switch (val->op) { + case DATA_I32: { + 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; + + case DATA_ADD: { + write_u8(LE, 0xc3, begin + 5, end); // ret + + codegen->offset_code += 1; + } break; - codegen->offset_code += 6; + default: + FAIL("Not implemented",); + } } } break; @@ -3413,7 +3491,7 @@ i64 unit_write_in_memory( // 4 bytes - flags o + 48 write_u16(LE, ELF_HEADER_SIZE, o + 52, o_end); write_u16(LE, ELF_PROGRAM_HEADER_SIZE, o + 54, o_end); - write_u16(LE, num_program_headers, o + 56, o_end); + // write_u16(LE, num_program_headers, o + 56, o_end); // 2 bytes - section header size o + 58 // 2 bytes - num section headers o + 60 // 2 bytes - string table section o + 62 @@ -3431,117 +3509,121 @@ i64 unit_write_in_memory( u8 *h = o + ELF_HEADER_SIZE; - // r/o elf header - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 4, h + 4, o_end); // flags (PF_R) - write_i64(LE, 0, h + 8, o_end); - write_i64(LE, base_address, h + 16, o_end); // virtual address - write_i64(LE, base_address, h + 24, o_end); // phisical address - write_i64(LE, ELF_HEADER_SIZE, h + 32, o_end); // size in file - write_i64(LE, ELF_HEADER_SIZE, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + num_program_headers = 0; // r/x code - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 5, h + 4, o_end); // flags (PF_X | PF_R) - write_i64(LE, rx_code_offset, h + 8, o_end); - write_i64(LE, rx_code_address, h + 16, o_end); // virtual address - write_i64(LE, rx_code_address, h + 24, o_end); // phisical address - write_i64(LE, rx_code_size, h + 32, o_end); // size in file - write_i64(LE, rx_code_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rx_code_size > 0) { + write_u32(LE, 1, h, o_end); // type (PT_LOAD) + write_u32(LE, 5, h + 4, o_end); // flags (PF_X | PF_R) + write_i64(LE, rx_code_offset, h + 8, o_end); + write_i64(LE, rx_code_address, h + 16, o_end); // virtual address + write_i64(LE, rx_code_address, h + 24, o_end); // phisical address + write_i64(LE, rx_code_size, h + 32, o_end); // size in file + write_i64(LE, rx_code_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/o data - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 4, h + 4, o_end); // flags (PF_R) - write_i64(LE, ro_data_offset, h + 8, o_end); - write_i64(LE, ro_data_address, h + 16, o_end); // virtual address - write_i64(LE, ro_data_address, h + 24, o_end); // phisical address - write_i64(LE, ro_data_size, h + 32, o_end); // size in file - write_i64(LE, ro_data_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (ro_data_size > 0) { + write_u32(LE, 1, h, o_end); // type (PT_LOAD) + write_u32(LE, 4, h + 4, o_end); // flags (PF_R) + write_i64(LE, ro_data_offset, h + 8, o_end); + write_i64(LE, ro_data_address, h + 16, o_end); // virtual address + write_i64(LE, ro_data_address, h + 24, o_end); // phisical address + write_i64(LE, ro_data_size, h + 32, o_end); // size in file + write_i64(LE, ro_data_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/w data - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, rw_data_offset, h + 8, o_end); - write_i64(LE, rw_data_address, h + 16, o_end); // virtual address - write_i64(LE, rw_data_address, h + 24, o_end); // phisical address - write_i64(LE, rw_data_size, h + 32, o_end); // size in file - write_i64(LE, rw_data_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rw_data_size > 0) { + write_u32(LE, 1, h, o_end); // type (PT_LOAD) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_data_offset, h + 8, o_end); + write_i64(LE, rw_data_address, h + 16, o_end); // virtual address + write_i64(LE, rw_data_address, h + 24, o_end); // phisical address + write_i64(LE, rw_data_size, h + 32, o_end); // size in file + write_i64(LE, rw_data_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/w zero values - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, rw_got_offset, h + 8, o_end); - write_i64(LE, rw_zval_address, h + 16, o_end); // virtual address - write_i64(LE, rw_zval_address, h + 24, o_end); // phisical address - write_i64(LE, 0, h + 32, o_end); // size in file - write_i64(LE, rw_zval_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rw_zval_size > 0) { + write_u32(LE, 1, h, o_end); // type (PT_LOAD) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_got_offset, h + 8, o_end); + write_i64(LE, rw_zval_address, h + 16, o_end); // virtual address + write_i64(LE, rw_zval_address, h + 24, o_end); // phisical address + write_i64(LE, 0, h + 32, o_end); // size in file + write_i64(LE, rw_zval_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/w GOT - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, rw_got_offset, h + 8, o_end); - write_i64(LE, rw_got_address, h + 16, o_end); // virtual address - write_i64(LE, rw_got_address, h + 24, o_end); // phisical address - write_i64(LE, rw_got_size, h + 32, o_end); // size in file - write_i64(LE, rw_got_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rw_got_size > 0) { + write_u32(LE, 1, h, o_end); // type (PT_LOAD) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_got_offset, h + 8, o_end); + write_i64(LE, rw_got_address, h + 16, o_end); // virtual address + write_i64(LE, rw_got_address, h + 24, o_end); // phisical address + write_i64(LE, rw_got_size, h + 32, o_end); // size in file + write_i64(LE, rw_got_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/w dynamic - write_u32(LE, 2, h, o_end); // type (PT_DYNAMIC) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, rw_dynamic_offset, h + 8, o_end); - write_i64(LE, rw_dynamic_address, h + 16, o_end); // virtual address - write_i64(LE, rw_dynamic_address, h + 24, o_end); // phisical address - write_i64(LE, rw_dynamic_size, h + 32, o_end); // size in file - write_i64(LE, rw_dynamic_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; - - // TLS segment - i64 tls_size_total = align(rw_tls_data_size, X86_64_PAGE_SIZE) + rw_tls_zval_size; - - write_u32(LE, 1, h, o_end); // type (PT_LOAD) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, rw_tls_data_offset, h + 8, o_end); - write_i64(LE, rw_tls_data_address, h + 16, o_end); // virtual address - write_i64(LE, rw_tls_data_address, h + 24, o_end); // phisical address - write_i64(LE, rw_tls_data_size, h + 32, o_end); // size in file - write_i64(LE, tls_size_total, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rw_dynamic_size) { + write_u32(LE, 2, h, o_end); // type (PT_DYNAMIC) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_dynamic_offset, h + 8, o_end); + write_i64(LE, rw_dynamic_address, h + 16, o_end); // virtual address + write_i64(LE, rw_dynamic_address, h + 24, o_end); // phisical address + write_i64(LE, rw_dynamic_size, h + 32, o_end); // size in file + write_i64(LE, rw_dynamic_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/w TLS data - write_u32(LE, 7, h, o_end); // type (PT_TLS) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, rw_tls_data_offset, h + 8, o_end); - write_i64(LE, rw_tls_data_address, h + 16, o_end); // virtual address - write_i64(LE, rw_tls_data_address, h + 24, o_end); // phisical address - write_i64(LE, rw_tls_data_size, h + 32, o_end); // size in file - write_i64(LE, rw_tls_data_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rw_tls_data_size > 0) { + write_u32(LE, 7, h, o_end); // type (PT_TLS) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_tls_data_offset, h + 8, o_end); + write_i64(LE, rw_tls_data_address, h + 16, o_end); // virtual address + write_i64(LE, rw_tls_data_address, h + 24, o_end); // phisical address + write_i64(LE, rw_tls_data_size, h + 32, o_end); // size in file + write_i64(LE, rw_tls_data_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } // r/w TLS zero values - write_u32(LE, 7, h, o_end); // type (PT_TLS) - write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) - write_i64(LE, output_size, h + 8, o_end); - write_i64(LE, rw_tls_zval_address, h + 16, o_end); // virtual address - write_i64(LE, rw_tls_zval_address, h + 24, o_end); // phisical address - write_i64(LE, 0, h + 32, o_end); // size in file - write_i64(LE, rw_tls_zval_size, h + 40, o_end); // size in memory - write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); - h += ELF_PROGRAM_HEADER_SIZE; + if (rw_tls_zval_size > 0) { + write_u32(LE, 7, h, o_end); // type (PT_TLS) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, output_size, h + 8, o_end); + write_i64(LE, rw_tls_zval_address, h + 16, o_end); // virtual address + write_i64(LE, rw_tls_zval_address, h + 24, o_end); // phisical address + write_i64(LE, 0, h + 32, o_end); // size in file + write_i64(LE, rw_tls_zval_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + ++num_program_headers; + } + + 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",); @@ -4062,6 +4144,12 @@ i64 n_call_by_name(i64 proc, c8 *name, i64 num_args, Var *args) { return n; } +i64 n_add(i64 proc, Var x, Var y) { + i64 n = node_data_add(&g_pool, x, y); + p_add(proc, n); + return n; +} + i64 n_ret(i64 proc, i64 num_vals, Var *vals) { i64 n = node_ctrl_ret(&g_pool, num_vals, vals); p_add(proc, n); @@ -4215,7 +4303,7 @@ b8 link_with_libc(void) { // ============================================================ - if (HOST != HOST_Linux) { + 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."); @@ -4231,6 +4319,34 @@ b8 link_with_libc(void) { return 1; } +b8 two_plus_two(void) { + i64 u = u_new(); + + i64 mainproc = p_new_entry(u); + + N_RET( + mainproc, + n_add(mainproc, n_i32(mainproc, 2), n_i32(mainproc, 2)) + ); + + u_elf_x86_64(u, "test_two_plus_two"); + + 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 = system("./test_two_plus_two"); + + if (WEXITSTATUS(ret) != 4) + return 0; + } + + return 1; +} + #endif // HELPERS i32 main(i32 argc, c8 **argv) { @@ -4250,7 +4366,8 @@ i32 main(i32 argc, c8 **argv) { } while (0) #if HELPERS - RUN_TEST_(link_with_libc); + // RUN_TEST_(link_with_libc); + RUN_TEST_(two_plus_two); #endif #undef RUN_TEST_ |