summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-07-17 16:34:12 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-07-17 16:34:12 +0200
commit71b727868d62f8a77285d6d04ee08df0b6a93376 (patch)
treeacdfb04ef3741763e7d3d19743ee696a35c61106
parent06c4451a6c23ffcc0601349c8768a5b489198285 (diff)
downloadbxgen-71b727868d62f8a77285d6d04ee08df0b6a93376.zip
Reading ELF object files into memory
-rwxr-xr-xbxgen.c308
1 files changed, 185 insertions, 123 deletions
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 <sys/stat.h>
#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;
}