From f9b4be038b0d40746a60e36ae0bd834ae066daa1 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Mon, 7 Apr 2025 15:28:29 +0100 Subject: [PATCH] Also read a.out objects --- aout.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- aout.h | 9 +- ld.c | 8 +- 3 files changed, 364 insertions(+), 8 deletions(-) diff --git a/aout.c b/aout.c index 3848688..0d99a45 100644 --- a/aout.c +++ b/aout.c @@ -12,6 +12,355 @@ #include "section.h" #include "symbol.h" +static void translate_relocation (struct reloc_entry *reloc, struct aout_relocation_info *input_reloc, struct section_part *part, struct aout_exec *exec_p) { + + unsigned long r_symbolnum = array_to_integer (input_reloc->r_symbolnum, 4); + + unsigned long r_address = array_to_integer (input_reloc->r_address, 4); + long symbolnum = (r_symbolnum & 0x7ffffff); + + if ((r_symbolnum >> 27) & 1) { /* ext */ + + reloc->symbol = part->of->symbol_arr + symbolnum; + + if (xstrcasecmp (reloc->symbol->name, "DGROUP") == 0) { + r_symbolnum &= ~(1LU << 27); + } + + } else { + + if (symbolnum == N_TEXT) { + reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - 3; + } else if (symbolnum == N_DATA) { + + reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - 2; + reloc->addend -= array_to_integer (exec_p->a_text, 4); + + } else if (symbolnum == N_BSS) { + + reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - 1; + reloc->addend -= (array_to_integer (exec_p->a_text, 4) + array_to_integer (exec_p->a_data, 4)); + + } else { + + report_at (program_name, 0, REPORT_INTERNAL_ERROR, "local input_reloc->r_symbolnum %#lx is not yet supported", symbolnum); + return; + + } + + } + + reloc->symbolnum = r_symbolnum; + reloc->offset = r_address; + + switch (1U << ((r_symbolnum >> 25) & 3)) { + + case 8: + + if ((r_symbolnum >> 24) & 1) { + + reloc->howto = &reloc_howtos[RELOC_TYPE_PC64]; + reloc->addend += reloc->offset + 8; + + } else { + reloc->howto = &reloc_howtos[RELOC_TYPE_64]; + } + + break; + + case 4: + + if ((r_symbolnum >> 24) & 1) { + + reloc->howto = &reloc_howtos[RELOC_TYPE_PC32]; + reloc->addend += reloc->offset + 4; + + } else { + reloc->howto = &reloc_howtos[RELOC_TYPE_32]; + } + + break; + + case 2: + + if ((r_symbolnum >> 24) & 1) { + + reloc->howto = &reloc_howtos[RELOC_TYPE_PC16]; + reloc->addend += reloc->offset + 2; + + } else { + reloc->howto = &reloc_howtos[RELOC_TYPE_16]; + } + + break; + + case 1: + + if ((r_symbolnum >> 24) & 1) { + + reloc->howto = &reloc_howtos[RELOC_TYPE_PC8]; + reloc->addend += reloc->offset + 4; + + } else { + reloc->howto = &reloc_howtos[RELOC_TYPE_8]; + } + + break; + + } + +} + +void read_aout_object (const char *filename, unsigned char *data, unsigned long data_size) { + + struct aout_exec *aout_exec; + struct aout_nlist *aout_nlist; + + const char *strtab; + unsigned long strtab_size; + + unsigned long num_symbols; + unsigned long i; + + struct section_part *part, *part_p_array[4] = { 0 }; + struct section *section, *bss_section; + + struct symbol *symbol, *old_symbol; + struct section_part *bss_part; + + struct aout_relocation_info *reloc_info; + struct object_file *of; + + unsigned char *pos = data; + + if ((pos - data + sizeof (*aout_exec) > data_size) || pos < data) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file"); + return; + + } + + aout_exec = (struct aout_exec *) pos; + pos += sizeof (*aout_exec); + + num_symbols = array_to_integer (aout_exec->a_syms, 4) / sizeof (*aout_nlist); + of = object_file_make (filename, num_symbols + 4); + + section = section_find_or_make (".text"); + section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_READONLY | SECTION_FLAG_CODE; + + part = section_part_new (section, of); + + part->content_size = array_to_integer (aout_exec->a_text, 4); + part->content = xmalloc (part->content_size); + + if ((pos - data + part->content_size > data_size) || pos < data) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file"); + return; + + } + + memcpy (part->content, pos, part->content_size); + pos += part->content_size; + + section_append_section_part (section, part); + part_p_array[1] = part; + + section = section_find_or_make (".data"); + section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_DATA; + + part = section_part_new (section, of); + + part->content_size = array_to_integer (aout_exec->a_data, 4); + part->content = xmalloc (part->content_size); + + if ((pos - data + part->content_size > data_size) || pos < data) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file"); + return; + + } + + memcpy (part->content, pos, part->content_size); + pos += part->content_size; + + section_append_section_part (section, part); + part_p_array[2] = part; + + bss_section = section = section_find_or_make (".bss"); + + section->flags = SECTION_FLAG_ALLOC; + section->is_bss = 1; + + part = section_part_new (section, of); + part->content_size = array_to_integer (aout_exec->a_bss, 4); + + section_append_section_part (section, part); + part_p_array[3] = part; + + pos += array_to_integer (aout_exec->a_syms, 4) + array_to_integer (aout_exec->a_trsize, 4) + array_to_integer (aout_exec->a_drsize, 4); + + if ((unsigned long) (pos - data + 4) > data_size || pos < data) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file"); + return; + + } + + strtab_size = array_to_integer (pos, 4); + + if (strtab_size < 4) { + + report_at (program_name, 0, REPORT_ERROR, "%s: invalid string table size %lu", filename, strtab_size); + return; + + } else { + + if ((pos - data + strtab_size > data_size) || pos < data) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file"); + return; + + } + + strtab = (char *) pos; + + } + + pos -= array_to_integer (aout_exec->a_syms, 4); + + for (i = 0; i < num_symbols; i++) { + + aout_nlist = (struct aout_nlist *) (pos + (i * sizeof (*aout_nlist))); + symbol = of->symbol_arr + i; + + if (array_to_integer (aout_nlist->n_strx, 4) < strtab_size) { + symbol->name = xstrdup (strtab + array_to_integer (aout_nlist->n_strx, 4)); + } else { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid offset into string table", filename); + return; + + } + + symbol->value = array_to_integer (aout_nlist->n_value, 4); + symbol->size = 0; + symbol->n_type = aout_nlist->n_type; + + if ((aout_nlist->n_type & N_TYPE) == N_UNDF || (aout_nlist->n_type & N_TYPE) == N_COMM) { + + if (symbol->value) { + + old_symbol = symbol_find (symbol->name); + + if (!old_symbol || symbol_is_undefined (old_symbol)) { + + bss_part = section_part_new (bss_section, of); + section_append_section_part (bss_section, bss_part); + + bss_part->content_size = symbol->size = symbol->value; + + symbol->part = bss_part; + symbol->value = 0; + symbol->section_number = 3; + + } else { + + if (symbol->value > old_symbol->size) { + old_symbol->part->content_size = old_symbol->size = symbol->value; + } + + symbol->part = 0; + symbol->value = 0; + symbol->section_number = UNDEFINED_SECTION_NUMBER; + + } + + } else { + + symbol->section_number = UNDEFINED_SECTION_NUMBER; + symbol->part = 0; + + } + + } else if ((aout_nlist->n_type & N_TYPE) == N_ABS) { + + symbol->section_number = ABSOLUTE_SECTION_NUMBER; + symbol->part = 0; + + } else if ((aout_nlist->n_type & N_TYPE) == N_TEXT) { + + symbol->section_number = 1; + symbol->part = part_p_array[1]; + + } else if ((aout_nlist->n_type & N_TYPE) == N_DATA) { + + symbol->section_number = 2; + symbol->part = part_p_array[2]; + symbol->value -= array_to_integer (aout_exec->a_text, 4); + + } else if ((aout_nlist->n_type & N_TYPE) == N_BSS) { + + symbol->section_number = 3; + symbol->part = part_p_array[3]; + symbol->value -= (array_to_integer (aout_exec->a_text, 4) + array_to_integer (aout_exec->a_data, 4)); + + } else { + + report_at (program_name, 0, REPORT_INTERNAL_ERROR, "unsupported nlist.n_type: %#x", aout_nlist->n_type); + return; + + } + + if ((aout_nlist->n_type & N_EXT) || (aout_nlist->n_type & N_TYPE) == N_UNDF || (aout_nlist->n_type & N_TYPE) == N_COMM) { + symbol_record_external_symbol (symbol); + } + + } + + for (i = 1; i < 4; i++) { + + symbol = of->symbol_arr + num_symbols + i; + part = part_p_array[i]; + + symbol->name = xstrdup (part->section->name); + symbol->value = 0; + symbol->size = 0; + symbol->part = part; + symbol->section_number = i; + + } + + pos -= (array_to_integer (aout_exec->a_trsize, 4) + array_to_integer (aout_exec->a_drsize, 4)); + part = part_p_array[1]; + + part->reloc_cnt = array_to_integer (aout_exec->a_trsize, 4) / sizeof (*reloc_info); + part->reloc_arr = xmalloc (sizeof (*part->reloc_arr) * part->reloc_cnt); + + for (i = 0; i < part->reloc_cnt; i++) { + + reloc_info = (struct aout_relocation_info *) (pos + (sizeof (*reloc_info) * i)); + translate_relocation (part->reloc_arr + i, reloc_info, part, aout_exec); + + } + + pos += array_to_integer (aout_exec->a_trsize, 4); + part = part_p_array[2]; + + part->reloc_cnt = array_to_integer (aout_exec->a_drsize, 4) / sizeof (*reloc_info); + part->reloc_arr = xmalloc (sizeof (*part->reloc_arr) * part->reloc_cnt); + + for (i = 0; i < part->reloc_cnt; i++) { + + reloc_info = (struct aout_relocation_info *) (pos + (sizeof (*reloc_info) * i)); + translate_relocation (part->reloc_arr + i, reloc_info, part, aout_exec); + + } + +} + + static unsigned long section_get_num_relocs (struct section *section) { unsigned long num_relocs = 0, i; @@ -40,7 +389,7 @@ static unsigned long section_get_num_relocs (struct section *section) { static unsigned char *write_relocs_for_section (unsigned char *pos, struct section *section) { struct section_part *part; - struct relocation_info rel; + struct aout_relocation_info rel; struct symbol *symbol; unsigned long size_log2, i, r_symbolnum; @@ -150,11 +499,11 @@ void aout_write (const char *filename) { integer_to_array (state->entry_point, exec.a_entry, 4); if (text_section) { - integer_to_array (section_get_num_relocs (text_section) * sizeof (struct relocation_info), exec.a_trsize, 4); + integer_to_array (section_get_num_relocs (text_section) * sizeof (struct aout_relocation_info), exec.a_trsize, 4); } if (data_section) { - integer_to_array (section_get_num_relocs (data_section) * sizeof (struct relocation_info), exec.a_drsize, 4); + integer_to_array (section_get_num_relocs (data_section) * sizeof (struct aout_relocation_info), exec.a_drsize, 4); } data_size = sizeof (exec); diff --git a/aout.h b/aout.h index 4113ba3..574ed31 100644 --- a/aout.h +++ b/aout.h @@ -22,8 +22,9 @@ struct aout_exec { #define N_TEXT 0x04 #define N_DATA 0x06 #define N_BSS 0x08 +#define N_COMM 0x12 -struct relocation_info { +struct aout_relocation_info { unsigned char r_address[4]; unsigned char r_symbolnum[4]; @@ -32,7 +33,7 @@ struct relocation_info { #define N_EXT 0x01 -/*struct aout_nlist { +struct aout_nlist { unsigned char n_strx[4]; unsigned char n_type; @@ -42,10 +43,12 @@ struct relocation_info { unsigned char n_value[4]; -};*/ +}; #define N_TYPE 0x1e + void aout_write (const char *filename); +void read_aout_object (const char *filename, unsigned char *data, unsigned long data_size); #define OMAGIC 0407 #define ZMAGIC 0413 diff --git a/ld.c b/ld.c index 2f95229..59ff6da 100644 --- a/ld.c +++ b/ld.c @@ -75,10 +75,14 @@ static void read_input_file (const char *filename) { } - if (data[0] == ((ELKS_MAGIC >> 8) & 0xff) && data[1] == (ELKS_MAGIC & 0xff)) { + /*if (memcmp (data, "!\n", 8) == 0) { + read_archive (filename, data, data_size); + } else*/ if (data[0] == 0x01 && data[1] == 0x03) { read_elks_object (filename, data, data_size); + } else if (data[0] == 0x07 && data[1] == 0x01) { + read_aout_object (filename, data, data_size); } else { - report_at (program_name, 0, REPORT_ERROR, "'%s' is not a valid object", filename); + report_at (program_name, 0, REPORT_ERROR, "%s: unrecognised file format", filename); } free (data); -- 2.34.1