From 71b727868d62f8a77285d6d04ee08df0b6a93376 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Wed, 17 Jul 2024 16:34:12 +0200 Subject: Reading ELF object files into memory --- bxgen.c | 308 ++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 185 insertions(+), 123 deletions(-) (limited to 'bxgen.c') diff --git a/bxgen.c b/bxgen.c index 661a008..7bee369 100755 --- a/bxgen.c +++ b/bxgen.c @@ -126,6 +126,10 @@ typedef char c8; // 8-bit character enum { // Log level ERROR = 0, + WARNING, + INFO, + VERBOSE, + TRACE, // For indices UNDEFINED = -1, @@ -414,11 +418,23 @@ void l_static(i64 unit, c8 *static_library); } while (0) #else # define BX_CHECK(condition, error_string, fail_result) \ - do { \ - b8 ok_ = (condition); \ - bx_assert(ok_, error_string, __LINE__, __FILE__); \ - if (!ok_) \ - return fail_result; \ + bx_assert((condition), error_string, __LINE__, __FILE__) +#endif + +#ifdef NDEBUG +# define BX_LAX(condition, error_string, fail_result) \ + do { \ + if (!(condition)) { \ + bx_log(WARNING, error_string, __LINE__, __FILE__); \ + } \ + } while (0) +#else +# define BX_LAX(condition, error_string, fail_result) \ + do { \ + if (!(condition)) { \ + bx_log(WARNING, error_string, __LINE__, __FILE__); \ + return fail_result; \ + } \ } while (0) #endif @@ -432,6 +448,8 @@ void l_static(i64 unit, c8 *static_library); return fail_result #endif +#define BX_LOG(log_level, message) bx_log(log_level, message, __LINE__, __FILE__) + i64 bx_align(i64 x, i64 a) { BX_CHECK(a > 0, "Invalid arguments", 0); return x + ((a - (x % a)) % a); @@ -469,6 +487,14 @@ i64 bx_str_len(c8 *s, c8 *s_max) { BX_FAIL("Buffer overflow", 0); } +i64 bx_str_len_or(c8 *s, c8 *s_max, i64 or_val) { + for (i64 len = 0; s + len < s_max; ++len) + if (s[len] == '\0') + return len; + + return or_val; +} + c8 *bx_find_char(c8 *s, c8 *s_end, c8 c) { BX_CHECK(s != NULL, "Invalid arguments", NULL); BX_CHECK(s_end != NULL, "Invalid arguments", NULL); @@ -1653,22 +1679,24 @@ void unit_write(Pool *pool, i64 unit, u16 target, i64 io_out, void *io_user_data // Intermediate buffer // - if (0) { - u8 static in_buffer[1024 * 1024 * 300]; // 300 MB - i64 static ar_offsets[128]; - i64 ar_count = 0; + // if (0) + { + u8 static im_buffer[1024 * 1024 * 300]; // 300 MB + i64 static im_offsets[10000]; + i64 im_num = 0; + i64 im_size = 0; // Read all dependency files into the memory // { + u8 static in_buffer[1024 * 1024 * 100]; // 100 MB + Unit *u = &pool->entities[unit].unit; for (i64 link_index = 0; link_index < u->link_count; ++link_index) { i64 id = u->links[link_index]; if (id == UNDEFINED) continue; - BX_CHECK(ar_count + 1 < (i64) (sizeof ar_offsets / sizeof *ar_offsets), "Buffer overflow",); - Unit *l = &pool->entities[id].unit; BX_CHECK(pool->entities[id].is_enabled, "Internal",); BX_CHECK(l->type == UNIT_LIBRARY_STATIC, "Link type not supported",); @@ -1676,123 +1704,101 @@ void unit_write(Pool *pool, i64 unit, u16 target, i64 io_out, void *io_user_data i64 f = io_open_read(l->name_size, l->name, io_user_data); io_seek(f, 0, IO_SEEK_END, io_user_data); - i64 size = io_tell(f, io_user_data); - io_seek(f, 0, IO_SEEK_BEGIN, io_user_data); - if (ar_count == 0) - ar_offsets[ar_count] = 0; - ar_offsets[ar_count + 1] = ar_offsets[ar_count] + bx_align(size, 8); - i64 n = io_read(f, size, in_buffer + ar_offsets[ar_count], io_user_data); - BX_CHECK(n == size, "Read failed",); - ++ar_count; - io_close(f, io_user_data); - } - } - - for (i64 ar_index = 0; ar_index < ar_count; ++ar_index) { - // ================================================================ - // - // Read AR library - - u8 *ar_begin = in_buffer + ar_offsets[ar_index]; - u8 *ar_end = in_buffer + ar_offsets[ar_index + 1]; - - u8 *ar_symbol_table = NULL; - u8 *ar_string_table = NULL; - - BX_CHECK(bx_mem_eq(ar_begin, AR_MAGIC, 8), "Invalid AR file",); - u8 *f_begin = ar_begin + 8; + i64 in_size = io_tell(f, io_user_data); + BX_CHECK(in_size <= (i64) (sizeof in_buffer), "AR file too big",); - while (f_begin + 60 < ar_end) { - u8 *f_id = f_begin; - u8 *f_size = f_begin + 48; - u8 *f_end = f_begin + 58; - u8 *f_data = f_begin + 60; - - i64 fn_size; - { - c8 buf[7] = {0}; - bx_mem_cpy(buf, f_size, 6); - fn_size = atoi(buf); - } - - fn_size = bx_align(fn_size, 2); - - BX_CHECK(bx_mem_eq(f_end, "\x60\x0a", 2), "Invalid AR file",); - BX_CHECK(f_begin + fn_size <= ar_end, "Buffer overflow",); - - if (bx_mem_eq(f_id, AR_SYMBOL_TABLE, 16)) { - // AR symbol table - // - - ar_symbol_table = f_data; + io_seek(f, 0, IO_SEEK_BEGIN, io_user_data); + i64 n = io_read(f, in_size, in_buffer, io_user_data); + BX_CHECK(n == in_size, "Read failed",); - f_begin = f_data + fn_size; - } else if (bx_mem_eq(f_id, AR_STRING_TABLE, 16)) { - // String table - // + io_close(f, io_user_data); - ar_string_table = f_data; + // ======================================================== + // + // Read AR library - f_begin = f_data + fn_size; - } else { - // ======================================================== - // - // Decode ELF object file + u8 *ar_begin = in_buffer; + u8 *ar_end = in_buffer + in_size; - u8 *elf_begin = f_data; - u8 *elf_end = f_begin + fn_size; - f_begin = elf_end; + BX_CHECK(bx_mem_eq(ar_begin, AR_MAGIC, 8), "Invalid AR file",); - u64 section_header_offset; - u16 section_count; - u16 string_table_index; - u16 string_table_offset; + u8 *f_begin = ar_begin + 8; - BX_CHECK(read_u8(LE, elf_begin, elf_end) == ELF_MAGIC[0], "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 1, elf_end) == ELF_MAGIC[1], "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 2, elf_end) == ELF_MAGIC[2], "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 3, elf_end) == ELF_MAGIC[3], "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 4, elf_end) == ELF_64, "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 5, elf_end) == ELF_2_LE, "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 6, elf_end) == ELF_VERSION, "Invalid ELF file",); + while (f_begin + 60 < ar_end) { + u8 *f_id = f_begin; + u8 *f_size = f_begin + 48; + u8 *f_end = f_begin + 58; + u8 *f_data = f_begin + 60; - u8 osabi = read_u8(LE, elf_begin + 7, elf_end); - BX_CHECK(osabi == ELF_SYS_V || osabi == ELF_LINUX, "Invalid ELF file",); - BX_CHECK(read_u8(LE, elf_begin + 8, elf_end) == ELF_ABI_VERSION, "Invalid ELF file",); + i64 fn_size; + { + c8 buf[7] = {0}; + bx_mem_cpy(buf, f_size, 6); + fn_size = atoi(buf); + } - BX_CHECK(read_u16(LE, elf_begin + 16, elf_end) == ELF_RELOCATABLE, "Invalid ELF file",); - BX_CHECK(read_u16(LE, elf_begin + 18, elf_end) == ELF_X86_64, "Invalid ELF file",); - BX_CHECK(read_u32(LE, elf_begin + 20, elf_end) == ELF_VERSION, "Invalid ELF file",); - BX_CHECK(read_u64(LE, elf_begin + 24, elf_end) == 0, "Invalid ELF file",); // entry - BX_CHECK(read_u64(LE, elf_begin + 32, elf_end) == 0, "Invalid ELF file",); // program header offset + fn_size = bx_align(fn_size, 2); - section_header_offset = read_u64(LE, elf_begin + 40, elf_end); + BX_CHECK(bx_mem_eq(f_end, "\x60\x0a", 2), "Invalid AR file",); + BX_CHECK(f_begin + fn_size <= ar_end, "Buffer overflow",); - BX_CHECK(read_u32(LE, elf_begin + 48, elf_end) == 0, "Invalid ELF file",); // flags - BX_CHECK(read_u16(LE, elf_begin + 52, elf_end) == ELF_HEADER_SIZE, "Invalid ELF file",); - BX_CHECK(read_u16(LE, elf_begin + 54, elf_end) == 0, "Invalid ELF file",); // program header size - BX_CHECK(read_u16(LE, elf_begin + 56, elf_end) == 0, "Invalid ELF file",); // program header count - BX_CHECK(read_u16(LE, elf_begin + 58, elf_end) == ELF_SECTION_HEADER_SIZE, "Invalid ELF file",); + if (!bx_mem_eq(f_id, AR_SYMBOL_TABLE, 16) && + !bx_mem_eq(f_id, AR_STRING_TABLE, 16)) { + // Read ELF object file - section_count = read_u16(LE, elf_begin + 60, elf_end); - string_table_index = read_u16(LE, elf_begin + 62, elf_end); + i64 delta_size = bx_align(fn_size, X86_64_ALIGNMENT); - string_table_offset = read_u64(LE, elf_begin + section_header_offset + string_table_index * ELF_SECTION_HEADER_SIZE + 24, elf_end); + BX_CHECK(im_size + delta_size < (i64) (sizeof im_buffer), "Out of memory",); + BX_CHECK(im_num + 1 < (i64) (sizeof im_offsets / sizeof *im_offsets), "Out of memory",); - (void) ar_symbol_table; - (void) ar_string_table; + bx_mem_cpy(im_buffer + im_size, f_data, fn_size); - (void) section_header_offset; - (void) section_count; - (void) string_table_index; - (void) string_table_offset; + im_offsets[im_num++] = im_size; + im_size += delta_size; + im_offsets[im_num] = im_size; + } f_begin = f_data + fn_size; - - // ======================================================== } } + + // ========================================================== + // + // Process ELF object files + + for (i64 elf_index = 0; elf_index < im_num; ++elf_index) { + u8 *elf_begin = im_buffer + im_offsets[elf_index]; + u8 *elf_end = im_buffer + im_offsets[elf_index + 1]; + + u8 osabi = read_u8(LE, elf_begin + 7, elf_end); + + BX_CHECK( read_u8 (LE, elf_begin, elf_end) == ELF_MAGIC[0], "Invalid ELF file",); + BX_CHECK( read_u8 (LE, elf_begin + 1, elf_end) == ELF_MAGIC[1], "Invalid ELF file",); + BX_CHECK( read_u8 (LE, elf_begin + 2, elf_end) == ELF_MAGIC[2], "Invalid ELF file",); + BX_CHECK( read_u8 (LE, elf_begin + 3, elf_end) == ELF_MAGIC[3], "Invalid ELF file",); + + BX_CHECK( read_u8 (LE, elf_begin + 4, elf_end) == ELF_64, "Unsupported ELF file",); + BX_CHECK( read_u8 (LE, elf_begin + 5, elf_end) == ELF_2_LE, "Unsupported ELF file",); + BX_CHECK( read_u8 (LE, elf_begin + 6, elf_end) == ELF_VERSION, "Unsupported ELF file",); + BX_CHECK( osabi == ELF_SYS_V || osabi == ELF_LINUX, "Unsupported ELF file",); + BX_CHECK( read_u8 (LE, elf_begin + 8, elf_end) == ELF_ABI_VERSION, "Unsupported ELF file",); + BX_CHECK( read_u16(LE, elf_begin + 16, elf_end) == ELF_RELOCATABLE, "Unsupported ELF file",); + BX_CHECK( read_u16(LE, elf_begin + 18, elf_end) == ELF_X86_64, "Unsupported ELF file",); + BX_CHECK( read_u32(LE, elf_begin + 20, elf_end) == ELF_VERSION, "Unsupported ELF file",); + + // We can ignore this + BX_CHECK( read_u64(LE, elf_begin + 24, elf_end) == 0, "Invalid ELF file",); // entry + BX_CHECK( read_u64(LE, elf_begin + 32, elf_end) == 0, "Invalid ELF file",); // program header offset + BX_CHECK( read_u32(LE, elf_begin + 48, elf_end) == 0, "Invalid ELF file",); // flags + BX_CHECK( read_u16(LE, elf_begin + 52, elf_end) == ELF_HEADER_SIZE, "Invalid ELF file",); + BX_CHECK( read_u16(LE, elf_begin + 54, elf_end) == 0, "Invalid ELF file",); // program header size + BX_CHECK( read_u16(LE, elf_begin + 56, elf_end) == 0, "Invalid ELF file",); // program header count + BX_CHECK( read_u16(LE, elf_begin + 58, elf_end) == ELF_SECTION_HEADER_SIZE, "Invalid ELF file",); + + } + + // ========================================================== } return; @@ -2564,13 +2570,63 @@ void io_chmod_exe(i64 f, void *user_data) { #include #endif +#define BX_LOGF(log_level, ...) \ + do { \ + c8 buf[1024] = {0}; \ + sprintf(buf, __VA_ARGS__); \ + BX_LOG(log_level, buf); \ + } while (0) + void bx_log(i32 log_level, c8 *message, u32 line, c8 *file) { + if (*message == '\0') { + fprintf(log_level == ERROR || log_level == WARNING ? stderr : stdout, "\n"); + return; + } + fflush(stdout); - if (log_level == ERROR) - fprintf(stderr, - "\r\x1b[41;1m\x1b[30mERROR:\x1b[40m\x1b[37m %s" - " \x1b[36m%s\x1b[34m:%d\x1b[37m\n", - message, file, line); + i32 len = 56 - (i32) bx_str_len_or(message, message + 56, 56); + switch (log_level) { + case ERROR: + fprintf(stderr, + "\r\x1b[41;1m\x1b[30m Error \x1b[40;0m\x1b[37m %s " + "%.*s \x1b[36m%s\x1b[34m:%d\x1b[37m\n", + message, len, + "................................................................", + file, line); + break; + + case WARNING: + fprintf(stderr, + "\r\x1b[43;1m\x1b[30m Warning \x1b[40;0m\x1b[37m %s " + "%.*s \x1b[36m%s\x1b[34m:%d\x1b[37m\n", + message, len, + "................................................................", + file, line); + break; + + case INFO: + fprintf(stdout, + "\r\x1b[42;1m\x1b[30m Info \x1b[40;0m\x1b[37m %s\n", + message); + break; + + case VERBOSE: + fprintf(stdout, + "\r\x1b[47;1m\x1b[30m Verbose \x1b[40;0m\x1b[37m %s\n", + message); + break; + + case TRACE: + fprintf(stdout, + "\r\x1b[45;1m\x1b[30m Trace \x1b[40;0m\x1b[37m %s " + "%.*s \x1b[36m%s\x1b[34m:%d\x1b[37m\n", + message, len, + "................................................................", + file, line); + break; + + default:; + } } void bx_assert(b8 condition, c8 *message, u32 line, c8 *file) { @@ -2767,13 +2823,19 @@ int main(int argc, char **argv) { (void) argc; (void) argv; - printf("host bit order: %s\n", host_bit_order() == BIT_LE ? "LE" : "BE"); - printf("host byte order: %s\n", host_byte_order() == BYTE_LE ? "LE" : "BE"); - printf("host word order: %s\n", host_word_order() == WORD_LE ? "LE" : "BE"); - printf("host dword order: %s\n", host_dword_order() == DWORD_LE ? "LE" : "BE"); - printf("host f64 dword order: %s\n\n", host_f64_dword_order() == F64_DWORD_LE ? "LE" : "BE"); + BX_LOG(ERROR, "Error example" ); + BX_LOG(WARNING, "Warning example"); + BX_LOG(INFO, "Info example" ); + BX_LOG(VERBOSE, "Verbose example"); + BX_LOG(TRACE, "Trace example" ); + + BX_LOGF(TRACE, "host bit order: %s", host_bit_order() == BIT_LE ? "LE" : "BE"); + BX_LOGF(TRACE, "host byte order: %s", host_byte_order() == BYTE_LE ? "LE" : "BE"); + BX_LOGF(TRACE, "host word order: %s", host_word_order() == WORD_LE ? "LE" : "BE"); + BX_LOGF(TRACE, "host dword order: %s", host_dword_order() == DWORD_LE ? "LE" : "BE"); + BX_LOGF(TRACE, "host f64 dword order: %s", host_f64_dword_order() == F64_DWORD_LE ? "LE" : "BE"); - printf("entity - %d bytes\n", (i32) sizeof(Entity)); + BX_LOGF(TRACE, "entity - %d bytes", (i32) sizeof(Entity)); i64 main = p_new("main"); i64 n0 = n_i64(42); @@ -2783,10 +2845,10 @@ int main(int argc, char **argv) { i64 u = u_new(); u_add(u, main); u_entry_point(u, main); - // l_static(u, "/lib/x86_64-linux-gnu/libc.a"); - l_static(u, "libtest.a"); + l_static(u, "/lib/x86_64-linux-gnu/libc.a"); + // l_static(u, "libtest.a"); - printf("Writing ELF x86_64 executable...\n"); + BX_LOG(VERBOSE, "Writing ELF x86_64 executable..."); u_elf_x86_64(u, "test_foo"); BX_CHECK(HO == LE, "Host data ordering is not compatible", -1); @@ -2795,7 +2857,7 @@ int main(int argc, char **argv) { BX_CHECK(WEXITSTATUS(ret) == 42, "Failure", -1); - printf("\nBye!\n"); + BX_LOG(INFO, "Bye!"); return 0; } -- cgit v1.2.3