Bug fixes
authorRobert Pengelly <robertapengelly@hotmail.com>
Sat, 3 May 2025 07:03:13 +0000 (08:03 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Sat, 3 May 2025 07:03:13 +0000 (08:03 +0100)
coff.c
ld.c
link.c
pe.c
reloc.h
section.c

diff --git a/coff.c b/coff.c
index c4cbff0c94a5b878bd31cb2bbfe2340286789d24..89aa544b17ab135de7a30f914f0c43bbf8ac4e85 100644 (file)
--- a/coff.c
+++ b/coff.c
@@ -70,6 +70,12 @@ static void translate_relocation (struct reloc_entry *reloc, struct coff_relocat
         
             reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
             break;
+        
+        default:
+        
+            /* There is no point in continuing, the object is broken. */
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "invalid relocation type 0x%04hx (origin object '%s')", array_to_integer (input->Type, 2), part->of->filename);
+            exit (EXIT_FAILURE);
     
     }
 
@@ -187,6 +193,7 @@ static unsigned long translate_Characteristics_to_section_flags (unsigned long C
 #define     IMAGE_SYM_DEBUG             -2
 
 #define     IMAGE_SYM_UNDEFINED         0
+#define     IMAGE_SYM_ABSOLUTE          1
 #define     IMAGE_SYM_CLASS_EXTERNAL    2
 
 void read_coff_object (const char *filename, unsigned char *data, unsigned long data_size) {
@@ -210,7 +217,9 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
     unsigned long i;
     
     struct section_part *bss_part = 0;
-    long bss_section_number;
+    struct section *bss_section = 0;
+    
+    long bss_section_number = 0;
     
     if ((pos - data + sizeof (*coff_hdr) > data_size) || pos < data) {
     
@@ -240,15 +249,7 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
     
     for (i = 0; i < no_sections; i++) {
     
-        section_hdr = (struct coff_section_table_entry *) ((unsigned char *) data + sizeof (struct coff_header) + sizeof (struct coff_section_table_entry) * i);
-        
-        if ((array_to_integer (section_hdr->Characteristics, 4) & IMAGE_SCN_LNK_REMOVE)) {
-        
-            part_p_array[i + 1] = 0;
-            continue;
-        
-        }
-        
+        section_hdr = (struct coff_section_table_entry *) (pos = (unsigned char *) data + sizeof (struct coff_header) + sizeof (struct coff_section_table_entry) * i);
         section_name = xstrndup (section_hdr->Name, 8);
         
         if (section_name[0] == '/') {
@@ -270,6 +271,15 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
             *p++ = '\0';
         }
         
+        if (array_to_integer (section_hdr->Characteristics, 4) & IMAGE_SCN_LNK_REMOVE) {
+        
+            part_p_array[i + 1] = 0;
+            
+            free (section_name);
+            continue;
+        
+        }
+        
         section = section_find_or_make (section_name);
         section->flags = translate_Characteristics_to_section_flags (array_to_integer (section_hdr->Characteristics, 4));
         
@@ -277,7 +287,12 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
             section->is_bss = 1;
         }
         
-        subsection = (p ? subsection_find_or_make (section, p) : 0);
+        if (p) {
+            subsection = subsection_find_or_make (section, p);
+        } else {
+            subsection = 0;
+        }
+        
         free (section_name);
         
         part = section_part_new (section, of);
@@ -293,6 +308,13 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
         
         }
         
+        if (section->is_bss) {
+        
+            bss_section_number = i + 1;
+            bss_section = section;
+        
+        }
+        
         if (array_to_integer (section_hdr->PointerToRelocations, 4) && array_to_integer (section_hdr->NumberOfRelocations, 2)) {
         
             unsigned long j, no_relocs;
@@ -337,7 +359,7 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
         struct symbol_table_entry *coff_symbol;
         struct symbol *symbol = of->symbol_arr + i;
         
-        int section_no, no_sections;
+        short section_no, no_sections;
         coff_symbol = (struct symbol_table_entry *) ((unsigned char *) data + array_to_integer (coff_hdr->PointerToSymbolTable, 4) + sizeof (struct symbol_table_entry) * i);
         
         if (memcmp (coff_symbol->Name, "\0\0\0\0", 4) == 0) {
@@ -357,37 +379,52 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
             symbol->name = xstrndup ((char *) coff_symbol->Name, 8);
         }
         
+        section_no = array_to_integer (coff_symbol->SectionNumber, 2);
+        
         symbol->value = array_to_integer (coff_symbol->value, 4);
-        symbol->section_number = array_to_integer (coff_symbol->SectionNumber, 2);
+        symbol->size = 0;
+        symbol->section_number = section_no;
         
-        section_no = array_to_integer (coff_symbol->SectionNumber, 2);
         no_sections = array_to_integer (coff_hdr->NumberOfSections, 2);
         
-        if (symbol->section_number == IMAGE_SYM_UNDEFINED) {
+        if (section_no == IMAGE_SYM_UNDEFINED) {
         
             if (symbol->value) {
             
-                if (!bss_part) {
+                struct symbol *old_symbol = symbol_find (symbol->name);
+                
+                if (!old_symbol || symbol_is_undefined (old_symbol)) {
                 
-                    struct section *section = section_find_or_make (".bss");
+                    if (bss_section) {
                     
-                    section->flags = translate_Characteristics_to_section_flags (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE);
-                    section->is_bss = 1;
+                        bss_section = section_find_or_make (".bss");
+                        
+                        bss_section->flags = translate_Characteristics_to_section_flags (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE);
+                        bss_section->is_bss = 1;
+                        
+                        bss_section_number = array_to_integer (coff_hdr->NumberOfSections, 2) ? array_to_integer (coff_hdr->NumberOfSections, 2) : 1;
                     
-                    bss_section_number = array_to_integer (coff_hdr->NumberOfSections, 2) ? array_to_integer (coff_hdr->NumberOfSections, 2) : 1;
+                    }
                     
-                    bss_part = section_part_new (section, of);
-                    bss_part->content_size = 0;
+                    bss_part = section_part_new (bss_section, of);
+                    section_append_section_part (bss_section, bss_part);
                     
-                    section_append_section_part (section, bss_part);
+                    bss_part->content_size = symbol->size - symbol->value;
+                    
+                    symbol->part = bss_part;
+                    symbol->value = 0;
+                    symbol->section_number = bss_section_number;
                 
-                }
+                } else {
                 
-                bss_part->content_size += symbol->value;
-                symbol->part = bss_part;
+                    if (symbol->value > old_symbol->size) {
+                        old_symbol->part->content_size = old_symbol->size = symbol->value;
+                    }
+                    
+                    symbol->value = 0;
+                    symbol->part = 0;
                 
-                symbol->value = bss_part->content_size - symbol->value;
-                symbol->section_number = bss_section_number;
+                }
             
             } else {
                 symbol->part = 0;
@@ -395,8 +432,11 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
         
         } else if (section_no > 0 && section_no <= no_sections) {
             symbol->part = part_p_array[section_no];
-        } else if (section_no == IMAGE_SYM_UNDEFINED || section_no == IMAGE_SYM_DEBUG) {
+        } else if (section_no == IMAGE_SYM_ABSOLUTE || section_no == IMAGE_SYM_DEBUG) {
+        
+            symbol->section_number = section_no;
             symbol->part = 0;
+        
         } else if (section_no > no_sections) {
         
             report_at (program_name, 0, REPORT_ERROR, "%s: invalid symbol SectionNumber: %hi", filename, section_no);
@@ -409,22 +449,24 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
         
         }
         
-        symbol->section_number = section_no;
-        
-        if (coff_symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
+        if (coff_symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL || section_no == IMAGE_SYM_UNDEFINED) {
             symbol_record_external_symbol (symbol);
         }
         
         if (coff_symbol->NumberOfAuxSymbols) {
         
-            for (i++; coff_symbol->NumberOfAuxSymbols; coff_symbol->NumberOfAuxSymbols--) {
+            unsigned long j;
             
-                symbol = of->symbol_arr + i;
+            for (j = 0; j < coff_symbol->NumberOfAuxSymbols; j++) {
+            
+                symbol = of->symbol_arr + i + 1 + j;
                 
                 memset (symbol, 0, sizeof (*symbol));
                 symbol->auxiliary = 1;
             
             }
+            
+            i += coff_symbol->NumberOfAuxSymbols;
         
         }
     
diff --git a/ld.c b/ld.c
index c67812055bc94e8b0b441081453f8fcded41a3a6..320490060f775594882547a32a37a20424f04938 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -95,15 +95,62 @@ struct offset_name_table {
 
 #define     ALREADY_READ                "Already read"
 
+static void read_archive_memeber (unsigned char *pos, const char *filename) {
+
+    struct ar_header *hdr = (struct ar_header *) pos;
+    
+    char *temp, *name;
+    unsigned long data_size;
+    
+    if (memcmp (pos, ALREADY_READ, sizeof (ALREADY_READ)) == 0) {
+        return;
+    }
+    
+    hdr = (struct ar_header *) pos;
+    
+    temp = xstrndup (hdr->name, sizeof (hdr->name));
+    strip_trailing_spaces (temp);
+    
+    if (temp) {
+    
+        unsigned long member_name_len = strlen (temp);
+        
+        if (member_name_len && temp[member_name_len - 1] == '/' && temp[0] != '/') {
+            temp[member_name_len - 1] = '\0';
+        }
+    
+    }
+    
+    name = xmalloc (strlen (filename) + 1 + strlen (temp) + 1 + 1);
+    sprintf (name, "%s(%s)", filename, temp);
+    
+    free (temp);
+    
+    temp = xstrndup (hdr->size, sizeof (hdr->size));
+    strip_trailing_spaces (temp);
+    
+    data_size = strtoul (temp, NULL, 10);
+    free (temp);
+    
+    read_object_file (name, pos + sizeof (*hdr), data_size);
+    free (name);
+    
+    memcpy (pos, ALREADY_READ, sizeof (ALREADY_READ));
+
+}
+
 static void read_archive (const char *filename, unsigned char *data) {
 
     unsigned char *pos = data + 8;
-    struct ar_header *hdr = (struct ar_header *) pos;
     
+    struct ar_header *hdr = (struct ar_header *) pos;
     struct offset_name_table *offset_name_table;
-    char *name, *temp, *string_table_pos;
     
-    unsigned long no_symbols, data_size, i;
+    char *string_table_pos, *name;
+    unsigned long no_symbols, i;
+    
+    unsigned long start_header_object_offset = 0;
+    unsigned long end_header_object_offset = 0;
     
     name = xstrndup (hdr->name, sizeof (hdr->name));
     strip_trailing_spaces (name);
@@ -129,11 +176,25 @@ static void read_archive (const char *filename, unsigned char *data) {
     for (i = 0; i < no_symbols; i++) {
     
         offset_name_table[i].offset = byte_array_to_integer (pos, 4, 1);
-        pos += 4;
-        
         offset_name_table[i].name = (char *) string_table_pos;
+        
         string_table_pos += strlen (offset_name_table[i].name) + 1;
+        pos += 4;
+    
+    }
+    
+    for (i = 0; i < no_symbols && (!start_header_object_offset || !end_header_object_offset); i++) {
     
+        if (strncmp (offset_name_table[i].name, "__head_", 7) == 0) {
+            start_header_object_offset = offset_name_table[i].offset;
+        } else if (strlen (offset_name_table[i].name) > 6 && strcmp (offset_name_table[i].name + strlen (offset_name_table[i].name) - 6, "_iname") == 0) {
+            end_header_object_offset = offset_name_table[i].offset;
+        }
+    
+    }
+    
+    if (start_header_object_offset) {
+        read_archive_memeber (data + start_header_object_offset, filename);
     }
     
     while (1) {
@@ -147,42 +208,11 @@ static void read_archive (const char *filename, unsigned char *data) {
                 continue;
             }
             
-            pos = data + offset_name_table[i].offset;
-            
-            if (memcmp (pos, ALREADY_READ, sizeof (ALREADY_READ)) == 0) {
+            if (offset_name_table[i].offset == start_header_object_offset || offset_name_table[i].offset == end_header_object_offset) {
                 continue;
             }
             
-            hdr = (struct ar_header *) pos;
-            
-            temp = xstrndup (hdr->name, sizeof (hdr->name));
-            strip_trailing_spaces (temp);
-            
-            if (temp) {
-            
-                unsigned long member_name_len = strlen (temp);
-                
-                if (member_name_len && temp[member_name_len - 1] == '/' && temp[0] != '/') {
-                    temp[member_name_len - 1] = '\0';
-                }
-            
-            }
-            
-            name = xmalloc (strlen (filename) + 1 + strlen (temp) + 1 + 1);
-            sprintf (name, "%s(%s)", filename, temp);
-            
-            free (temp);
-            
-            temp = xstrndup (hdr->size, sizeof (hdr->size));
-            strip_trailing_spaces (temp);
-            
-            data_size = strtoul (temp, NULL, 10);
-            free (temp);
-            
-            read_object_file (name, pos + sizeof (*hdr), data_size);
-            free (name);
-            
-            memcpy (pos, ALREADY_READ, sizeof (ALREADY_READ));
+            read_archive_memeber (data + offset_name_table[i].offset, filename);
             change = 1;
         
         }
@@ -193,6 +223,10 @@ static void read_archive (const char *filename, unsigned char *data) {
     
     }
     
+    if (end_header_object_offset) {
+        read_archive_memeber (data + end_header_object_offset, filename);
+    }
+    
     free (offset_name_table);
 
 }
@@ -275,8 +309,6 @@ int main (int argc, char **argv) {
     
     }
     
-    sections_destroy_empty_before_collapse ();
-    
     if (state->format == LD_FORMAT_I386_COFF) {
         coff_before_link ();
     } else if (state->format == LD_FORMAT_I386_PE) {
diff --git a/link.c b/link.c
index 7958454b650bf3a938d5aeb4b87f671da54e7cfd..3c4dc83650032c164ccf7871cea8f7bdfaf90a38 100644 (file)
--- a/link.c
+++ b/link.c
 
 struct reloc_howto reloc_howtos[RELOC_TYPE_END] = {
 
-    {   0,  0,  0,  0,  0,  "RELOC_TYPE_IGNORED",   0,  0   },
+    {   0,  0,  0,  0,  0,  "RELOC_TYPE_IGNORED",       0,  0   },
     
-    {   8,  0,  0,  0,  0,  "RELOC_TYPE_64",        0,  0   },
-    {   8,  1,  0,  0,  0,  "RELOC_TYPE_PC64",      0,  0   },
+    {   8,  0,  0,  0,  0,  "RELOC_TYPE_64",            0,  0   },
+    {   4,  0,  0,  0,  0,  "RELOC_TYPE_32",            0,  0   },
+    {   2,  0,  0,  0,  0,  "RELOC_TYPE_16",            0,  0   },
+    {   1,  0,  0,  0,  0,  "RELOC_TYPE_8",             0,  0   },
     
-    {   4,  0,  0,  0,  0,  "RELOC_TYPE_32",        0,  0   },
-    {   4,  1,  0,  0,  0,  "RELOC_TYPE_PC32",      0,  0   },
+    {   8,  1,  0,  0,  0,  "RELOC_TYPE_PC64",          0,  0   },
+    {   4,  1,  0,  0,  0,  "RELOC_TYPE_PC32",          0,  0   },
+    {   2,  1,  0,  0,  0,  "RELOC_TYPE_PC16",          0,  0   },
+    {   1,  1,  0,  0,  0,  "RELOC_TYPE_PC8",           0,  0   },
     
-    {   2,  0,  0,  0,  0,  "RELOC_TYPE_16",        0,  0   },
-    {   2,  1,  0,  0,  0,  "RELOC_TYPE_PC16",      0,  0   },
-    
-    {   1,  0,  0,  0,  0,  "RELOC_TYPE_8",         0,  0   },
-    {   1,  1,  0,  0,  0,  "RELOC_TYPE_PC8",       0,  0   }
+    {   4,  0,  1,  0,  0,  "RELOC_TYPE_32_NO_BASE",    0,  0   }
 
 };
 
diff --git a/pe.c b/pe.c
index 0efc358170d8a7c006d80e08e31d64ea899fb646..59c874037182c86ba142b5485da057623b0f2199 100644 (file)
--- a/pe.c
+++ b/pe.c
@@ -664,27 +664,19 @@ void pe_before_link (void) {
     
     part = section_part_new (section, object_file_make (FAKE_LD_FILENAME, 0));
     
-    part->content_size = sizeof (struct pe_import_directory_table);
-    part->content = xmalloc (part->content_size);
-    
+    part->content = xmalloc (part->content_size = sizeof (struct pe_import_directory_table));
     subsection_append_section_part (subsection, part);
     
     if (!(subsection = subsection_find (section, "5"))) {
         return;
     }
     
-    iat_first_part = subsection->first_part;
-    
-    if (!iat_first_part) {
+    if (!(iat_first_part = subsection->first_part)) {
         return;
     }
     
-    for (part = iat_first_part; ; part = part->next) {
-    
-        if (!part->next) {
-            break;
-        }
-    
+    for (part = iat_first_part; part->next; part = part->next) {
+        ;
     }
     
     iat_last_part = part;
@@ -904,10 +896,10 @@ void pe_write (const char *filename) {
                 case 12:
                 
                     /* IMPORT Address Table. */
-                    if ((section = section_find (".idata"))) {
+                    if ((section = section_find (".idata")) && iat_first_part) {
                     
                         write741_to_byte_array (idd->VirtualAddress, iat_first_part->rva);
-                        write741_to_byte_array (idd->Size, iat_first_part->rva + iat_last_part->content_size);
+                        write741_to_byte_array (idd->Size, iat_last_part->rva + iat_last_part->content_size - iat_first_part->rva);
                     
                     }
                     
diff --git a/reloc.h b/reloc.h
index f5e64626a4df4e4c26940c599735f7f144098a40..5385dc3fddadf26867b60ad641130fd9efce3ea0 100644 (file)
--- a/reloc.h
+++ b/reloc.h
@@ -9,15 +9,13 @@ enum {
     RELOC_TYPE_IGNORED,
     
     RELOC_TYPE_64,
-    RELOC_TYPE_PC64,
-    
     RELOC_TYPE_32,
-    RELOC_TYPE_PC32,
-    
     RELOC_TYPE_16,
-    RELOC_TYPE_PC16,
-    
     RELOC_TYPE_8,
+    
+    RELOC_TYPE_PC64,
+    RELOC_TYPE_PC32,
+    RELOC_TYPE_PC16,
     RELOC_TYPE_PC8,
     
     RELOC_TYPE_32_NO_BASE,
index 2c9dcbf83c698ca4fc5b9bb02e1f7322cb3d4906..2c986d90cf4afba1bf444831c5aa1546f228a2de 100644 (file)
--- a/section.c
+++ b/section.c
@@ -14,14 +14,13 @@ static struct section **last_section_p = &all_sections;
 
 static struct section *discarded_sections = 0;
 
-struct object_file *object_file_make (const char *filename, unsigned long symbol_cnt) {
+struct object_file *object_file_make (const char *filename, unsigned long symbol_count) {
 
     struct object_file *of = xmalloc (sizeof (*of));
-    
     of->filename = xstrdup (filename);
     
-    of->symbol_arr = symbol_cnt ? xmalloc (sizeof (*of->symbol_arr) * symbol_cnt) : 0;
-    of->symbol_cnt = symbol_cnt;
+    of->symbol_arr = symbol_count ? xmalloc (sizeof (*of->symbol_arr) * symbol_count) : 0;
+    of->symbol_cnt = symbol_count;
     
     *last_object_file_p = of;
     last_object_file_p = &of->next;
@@ -89,8 +88,8 @@ void section_append_section_part (struct section *section, struct section_part *
 void sections_destroy_empty_before_collapse (void) {
 
     struct section *section, **next_p;
-    
     struct section_part *part;
+    
     struct subsection *subsection;
     
     for (next_p = &all_sections, section = *next_p; section; section = *next_p) {
@@ -140,12 +139,8 @@ void section_write (struct section *section, unsigned char *memory) {
     
     for (part = section->first_part; part; part = part->next) {
     
-        if (part->content_size > 0) {
-        
-            memcpy (memory, part->content, part->content_size);
-            memory += part->content_size;
-        
-        }
+        memcpy (memory, part->content, part->content_size);
+        memory += part->content_size;
     
     }
 
@@ -197,9 +192,9 @@ struct subsection *subsection_find_or_make (struct section *section, const char
         subsection = xmalloc (sizeof (*subsection));
         
         subsection->name = xstrdup (name);
-        subsection->next = *next_p;
         subsection->last_part_p = &subsection->first_part;
         
+        subsection->next = *next_p;
         *next_p = subsection;
     
     }