summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-07-17 15:16:13 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-07-17 15:16:13 +0200
commit06c4451a6c23ffcc0601349c8768a5b489198285 (patch)
tree916c1b85be91d550320336a044f2569f5bbf6949
parent9baf560a2b48912e905fc2ff1801d00080875198 (diff)
downloadbxgen-06c4451a6c23ffcc0601349c8768a5b489198285.zip
Add symbol and relocation procs
-rwxr-xr-xbxgen.c302
1 files changed, 208 insertions, 94 deletions
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";
@@ -1210,6 +1220,12 @@ typedef struct {
} Offset_Size;
typedef struct {
+ u8 * begin;
+ u8 * end;
+ Offset_Size elf;
+} Buffer_Context;
+
+typedef struct {
u64 offset;
u16 count;
} Offset_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",);