Also read a.out objects
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 7 Apr 2025 14:28:29 +0000 (15:28 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 7 Apr 2025 14:28:29 +0000 (15:28 +0100)
aout.c
aout.h
ld.c

diff --git a/aout.c b/aout.c
index 3848688295fd5c5eee18f2ffbce3644e89d53bda..0d99a4524b0c5a2b5febec878e1a1647322da380 100644 (file)
--- a/aout.c
+++ b/aout.c
 #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 4113ba3ca7b364d5c918fa63b002599b6a926ab1..574ed319e740581ab57f4a751ecb05259be7d2a0 100644 (file)
--- 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 2f95229f4f6c4a40509daee6e955529f9860e6d2..59ff6da4a140c8620026634b01c7f826415a92c4 100644 (file)
--- 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, "!<arch>\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);