From 06c4451a6c23ffcc0601349c8768a5b489198285 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Wed, 17 Jul 2024 15:16:13 +0200 Subject: Add symbol and relocation procs --- bxgen.c | 302 ++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 208 insertions(+), 94 deletions(-) (limited to 'bxgen.c') diff --git a/bxgen.c b/bxgen.c index ea1cdfe..661a008 100755 --- a/bxgen.c +++ b/bxgen.c @@ -1188,6 +1188,16 @@ enum { ELF_SYMBOL_ENTRY_SIZE = 24, ELF_REL_ENTRY_SIZE = 16, ELF_RELA_ENTRY_SIZE = 24, + + SYM_NONE = 0, + SYM_PROC, + SYM_DATA, + SYM_DATA_UNDEFINED, + SYM_DATA_THREAD_LOCAL, + + BIND_LOCAL = 0, + BIND_GLOBAL, + BIND_WEAK, }; c8 ELF_MAGIC[4] = "\x7f" "ELF"; @@ -1209,6 +1219,12 @@ typedef struct { u64 size; } Offset_Size; +typedef struct { + u8 * begin; + u8 * end; + Offset_Size elf; +} Buffer_Context; + typedef struct { u64 offset; u16 count; @@ -1218,24 +1234,27 @@ typedef struct { Offset_Size name; u32 type; u64 flags; + u64 alignment; + u64 entry_size; Offset_Size data; } Section_Header; typedef struct { Offset_Size name; - u8 info; + u8 type; + u8 bind; Offset_Size value; } Symbol_Entry; typedef struct { - Offset_Size dst; - Offset_Size symbol; + Offset_Size name; + u64 dst; u32 type; } Rel_Entry; typedef struct { - Offset_Size dst; - Offset_Size symbol; + Offset_Size name; + u64 dst; u32 type; i64 addent; } Rela_Entry; @@ -1265,56 +1284,58 @@ u32 ar_find_symbol_offset_by_name(u8 *ar_symbol_table, u8 *ar_end, c8 *name, c8 ++s; } - BX_FAIL("Symbol not found", -1); -} - -u16 elf_section_names_table_index( - u8 *elf_begin, - u8 *elf_end -) { - return read_u16(LE, elf_begin + 62, elf_end); + BX_FAIL("Symbol not found", 0); } Offset_Count elf_section_headers( - u8 *elf_begin, - u8 *elf_end + Buffer_Context b ) { + u8 *begin = b.begin + b.elf.offset; + u8 *end = begin + b.elf.size; + + BX_CHECK(end <= b.end, "Buffer overflow", (Offset_Count) {0}); + return (Offset_Count) { - .offset = read_u64(LE, elf_begin + 40, elf_end), - .count = read_u16(LE, elf_begin + 60, elf_end), + .offset = b.elf.offset + read_u64(LE, begin + 40, end), + .count = read_u16(LE, begin + 60, end), }; } u64 elf_section_header_offset( - u8 *elf_begin, - u8 *elf_end, - u16 index + Buffer_Context b, + u16 index ) { - return elf_section_headers(elf_begin, elf_end).offset + ELF_SECTION_HEADER_SIZE * index; + return elf_section_headers(b).offset + ELF_SECTION_HEADER_SIZE * index; } Offset_Size elf_section_names_data( - u8 *elf_begin, - u8 *elf_end + Buffer_Context b ) { - u16 string_table_index = elf_section_names_table_index(elf_begin, elf_end); + u8 *elf_begin = b.begin + b.elf.offset; + u8 *elf_end = elf_begin + b.elf.size; + BX_CHECK(elf_end <= b.end, "Buffer overflow", (Offset_Size) {0}); - u8 *begin = elf_begin + elf_section_header_offset(elf_begin, elf_end, string_table_index); + u16 string_table_index = read_u16(LE, elf_begin + 62, elf_end); + + u8 *begin = elf_begin + elf_section_header_offset(b, string_table_index); return (Offset_Size) { - .offset = read_u64(LE, begin + 24, elf_end), + .offset = b.elf.offset + read_u64(LE, begin + 24, elf_end), .size = read_u64(LE, begin + 32, elf_end), }; } Offset_Size elf_name_in_string_table( - u8 * elf_begin, - u8 * elf_end, - Offset_Size string_table, - u32 name_offset + Buffer_Context b, + Offset_Size string_table, + u32 name_offset ) { + u8 *elf_begin = b.begin + b.elf.offset; + u8 *elf_end = elf_begin + b.elf.size; + BX_CHECK(elf_end <= b.end, "Buffer overflow", (Offset_Size) {0}); + u64 offset = string_table.offset + name_offset; - c8 *begin = (c8 *) (elf_begin + offset); + c8 *begin = (c8 *) (b.begin + offset); c8 *end = begin + string_table.size; BX_CHECK(end <= (c8 *) elf_end, "Buffer overflow", (Offset_Size) {0}); @@ -1326,16 +1347,19 @@ Offset_Size elf_name_in_string_table( } u16 elf_find_section_index_by_name( - u8 *elf_begin, - u8 *elf_end, - c8 *name, - u32 name_size + Buffer_Context b, + c8 * name, + u32 name_size ) { - Offset_Count headers = elf_section_headers(elf_begin, elf_end); - Offset_Size names = elf_section_names_data(elf_begin, elf_end); + u8 *elf_begin = b.begin + b.elf.offset; + u8 *elf_end = elf_begin + b.elf.size; + BX_CHECK(elf_end <= b.end, "Buffer overflow", 0); + + Offset_Count headers = elf_section_headers(b); + Offset_Size names = elf_section_names_data(b); for (u16 i = 0; i < headers.count; ++i) { - u8 *begin = elf_begin + headers.offset + i * ELF_SECTION_HEADER_SIZE; + u8 *begin = b.begin + headers.offset + i * ELF_SECTION_HEADER_SIZE; u32 name_offset = read_u32(LE, begin, elf_end); if (name_offset + name_size <= names.size && @@ -1343,55 +1367,91 @@ u16 elf_find_section_index_by_name( return i; } - BX_FAIL("Not found", -1); + BX_FAIL("Not found", 0); } Section_Header elf_section( - u8 *elf_begin, - u8 *elf_end, - u16 index + Buffer_Context b, + u16 index ) { - Offset_Size names = elf_section_names_data(elf_begin, elf_end); - u8 * begin = elf_begin + elf_section_header_offset(elf_begin, elf_end, index); - u32 name_index = read_u32(LE, begin, elf_end); + Offset_Size names = elf_section_names_data(b); + u8 * begin = b.begin + elf_section_header_offset(b, index); + u8 * end = b.begin + b.elf.offset + b.elf.size; + BX_CHECK(end <= b.end, "Buffer overflow", (Section_Header) {0}); + + u32 name_index = read_u32(LE, begin, end); return (Section_Header) { - .name = elf_name_in_string_table( - elf_begin, - elf_end, - names, - name_index - ), - .type = read_u32(LE, begin + 4, elf_end), - .flags = read_u64(LE, begin + 8, elf_end), + .name = elf_name_in_string_table(b, names, name_index), + .type = read_u32(LE, begin + 4, end), + .flags = read_u64(LE, begin + 8, end), + .alignment = read_u64(LE, begin + 48, end), + .entry_size = read_u64(LE, begin + 56, end), .data = { - .offset = read_u64(LE, begin + 24, elf_end), - .size = read_u64(LE, begin + 32, elf_end), + .offset = b.elf.offset + read_u64(LE, begin + 24, end), + .size = read_u64(LE, begin + 32, end), }, }; } Section_Header elf_find_section_by_name( - u8 *elf_begin, - u8 *elf_end, - c8 *name, - u32 name_size + Buffer_Context b, + c8 * name, + u32 name_size +) { + return elf_section(b, elf_find_section_index_by_name(b, name, name_size)); +} + +u16 elf_find_related_section_index( + Buffer_Context b, + u16 section_index +) { + Offset_Size name = elf_section(b, section_index).name; + c8 *begin = (c8 *) b.begin + name.offset; + c8 *end = begin + name.size; + + BX_CHECK(end <= (c8 *) b.end, "Buffer overflow", 0); + BX_CHECK(end <= (c8 *) b.begin + b.elf.offset + b.elf.size, "Buffer overflow", 0); + + if (*begin == '.') + ++begin; + while (begin < end && *begin != '.') + ++begin; + + BX_CHECK(begin < end, "Not found", 0); + + u32 size = (u32) (end - begin); + Offset_Size check_name = elf_section(b, section_index - 1).name; + + BX_CHECK(b.begin + check_name.offset + size <= b.end, "Buffer overflow", 0); + BX_CHECK(b.begin + check_name.offset + size <= b.begin + b.elf.offset + b.elf.size, "Buffer overflow", 0); + + if (check_name.size == size && + bx_mem_eq(b.begin + check_name.offset, begin, size)) + return section_index - 1; + + return elf_find_section_index_by_name(b, begin, (u32) (end - begin)); +} + +u16 elf_num_entries( + Buffer_Context b, + u8 section_index ) { - return elf_section(elf_begin, elf_end, elf_find_section_index_by_name(elf_begin, elf_end, name, name_size)); + Section_Header h = elf_section(b, section_index); + return h.data.size / h.entry_size; } Symbol_Entry elf_symbol( - u8 * elf_begin, - u8 * elf_end, - Offset_Size string_table, - u16 section_index, - u16 symbol_index + Buffer_Context b, + Offset_Size string_table, + Offset_Size symbol_table, + u16 symbol_index ) { - Offset_Size data = elf_section(elf_begin, elf_end, section_index).data; - u8 * begin = elf_begin + data.offset + symbol_index * ELF_SYMBOL_ENTRY_SIZE; - u8 * end = elf_begin + data.offset + data.size; + u8 *begin = b.begin + symbol_table.offset + symbol_index * ELF_SYMBOL_ENTRY_SIZE; + u8 *end = b.begin + symbol_table.offset + symbol_table.size; - BX_CHECK(end <= elf_end, "Buffer overflow", (Symbol_Entry) {0}); + BX_CHECK(end <= b.end, "Buffer overflow", (Symbol_Entry) {0}); + BX_CHECK(end <= b.begin + b.elf.offset + b.elf.size, "Buffer overflow", (Symbol_Entry) {0}); u32 sym_name = read_u32(LE, begin, end); u8 sym_info = read_u8 (LE, begin + 4, end); @@ -1399,13 +1459,24 @@ Symbol_Entry elf_symbol( u64 sym_value = read_u64(LE, begin + 8, end); u64 sym_size = read_u64(LE, begin + 16, end); - Offset_Size dst = elf_section(elf_begin, elf_end, sym_shndx).data; + Offset_Size dst = elf_section(b, sym_shndx).data; BX_CHECK(sym_value + sym_size <= dst.size, "Buffer overflow", (Symbol_Entry) {0}); + u8 type = (sym_info & 0xf) == 1 ? SYM_DATA : + (sym_info & 0xf) == 2 ? SYM_PROC : + (sym_info & 0xf) == 5 ? SYM_DATA_UNDEFINED : + (sym_info & 0xf) == 6 ? SYM_DATA_THREAD_LOCAL : + SYM_NONE; + + u8 bind = (sym_info >> 4) == 1 ? BIND_GLOBAL : + (sym_info >> 4) == 2 ? BIND_WEAK : + BIND_LOCAL; + return (Symbol_Entry) { - .name = elf_name_in_string_table(elf_begin, elf_end, string_table, sym_name), - .info = sym_info, + .name = elf_name_in_string_table(b, string_table, sym_name), + .type = type, + .bind = bind, .value = { .offset = dst.offset + sym_value, .size = sym_size, @@ -1414,41 +1485,84 @@ Symbol_Entry elf_symbol( } Rel_Entry elf_rel( - u8 * elf_begin, - u8 * elf_end, - Offset_Size string_table, - u16 section_index, - u16 rel_index + Buffer_Context b, + Offset_Size string_table, + Offset_Size symbol_table, + u16 section_index, + u16 rel_index ) { - (void) elf_begin; - (void) elf_end; - (void) string_table; - (void) section_index; - (void) rel_index; + Offset_Size data = elf_section(b, section_index).data; + u8 * begin = b.begin + data.offset + rel_index * ELF_REL_ENTRY_SIZE; + u8 * end = begin + ELF_REL_ENTRY_SIZE; + + BX_CHECK(end <= b.end, "Buffer overflow", (Rel_Entry) {0}); + BX_CHECK(end <= b.begin + b.elf.offset + b.elf.size, "Buffer overflow", (Rel_Entry) {0}); + + u64 rel_offset = read_u64(LE, begin, end); + u32 rel_type = read_u32(LE, begin + 8, end); + u32 rel_sym = read_u32(LE, begin + 12, end); + + Symbol_Entry sym = elf_symbol(b, string_table, symbol_table, rel_sym); return (Rel_Entry) { - 0 + .name = sym.name, + .dst = data.offset + rel_offset, + .type = rel_type, }; } Rela_Entry elf_rela( - u8 * elf_begin, - u8 * elf_end, - Offset_Size string_table, - u16 section_index, - u16 rela_index + Buffer_Context b, + Offset_Size string_table, + Offset_Size symbol_table, + u16 section_index, + u16 rela_index ) { - (void) elf_begin; - (void) elf_end; - (void) string_table; - (void) section_index; - (void) rela_index; + Offset_Size data = elf_section(b, section_index).data; + u8 * begin = b.begin + data.offset + rela_index * ELF_RELA_ENTRY_SIZE; + u8 * end = begin + ELF_RELA_ENTRY_SIZE; + + BX_CHECK(end <= b.end, "Buffer overflow", (Rela_Entry) {0}); + BX_CHECK(end <= b.begin + b.elf.offset + b.elf.size, "Buffer overflow", (Rela_Entry) {0}); + + u64 rela_offset = read_u64(LE, begin, end); + u32 rela_type = read_u32(LE, begin + 8, end); + u32 rela_sym = read_u32(LE, begin + 12, end); + i64 rela_addent = read_i64(LE, begin + 16, end); + + Symbol_Entry sym = elf_symbol(b, string_table, symbol_table, rela_sym); return (Rela_Entry) { - 0 + .name = sym.name, + .dst = data.offset + rela_offset, + .type = rela_type, + .addent = rela_addent, }; } +Symbol_Entry elf_find_symbol_by_name( + Buffer_Context b, + Offset_Size string_table, + u32 symbol_table_index, + c8 * name, + u32 name_size +) { + u32 num_symbols = elf_num_entries(b, symbol_table_index); + + for (u32 i = 0; i < num_symbols; ++i) { + Offset_Size symbol_table = elf_section(b, symbol_table_index).data; + Symbol_Entry sym = elf_symbol(b, string_table, symbol_table, i); + + BX_CHECK(b.begin + sym.name.offset + name_size <= b.end, "Buffer overflow", (Symbol_Entry) {0}); + BX_CHECK(sym.name.offset + name_size <= b.elf.size, "Buffer overflow", (Symbol_Entry) {0}); + + if (name_size == sym.name.size && bx_mem_eq(name, b.begin + sym.name.offset, name_size)) + return sym; + } + + BX_FAIL("Not found", (Symbol_Entry) {0}); +} + void unit_write(Pool *pool, i64 unit, u16 target, i64 io_out, void *io_user_data) { BX_CHECK(pool != NULL && pool->entities != NULL, "Invalid arguments",); BX_CHECK(pool->entities[unit].is_enabled, "Unit does not exist",); -- cgit v1.2.3