Added COFF object support and bug fixes
authorRobert Pengelly <robertapengelly@hotmail.com>
Wed, 30 Apr 2025 21:30:28 +0000 (22:30 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Wed, 30 Apr 2025 21:30:28 +0000 (22:30 +0100)
coff.c
coff.h
ld.c
omf.c
omf.h
pe.c
pe.h
reloc.h
section.c
section.h

diff --git a/coff.c b/coff.c
index daae1980eca4e23d57b5f132447743d9fecb3144..c4cbff0c94a5b878bd31cb2bbfe2340286789d24 100644 (file)
--- a/coff.c
+++ b/coff.c
 #include    "section.h"
 #include    "write7x.h"
 
+struct string_table_header {
+    unsigned char StringTableSize[4];
+};
+
+struct symbol_table_entry {
+
+    unsigned char Name[8];
+    unsigned char value[4];
+    
+    unsigned char SectionNumber[2];
+    unsigned char Type[2];
+    
+    unsigned char StorageClass;
+    unsigned char NumberOfAuxSymbols;
+
+};
+
+static void translate_relocation (struct reloc_entry *reloc, struct coff_relocation_entry *input, struct section_part *part) {
+
+    reloc->symbol = part->of->symbol_arr + array_to_integer (input->SymbolTableIndex, 4);
+    reloc->offset = array_to_integer (input->VirtualAddress, 4);
+    
+    switch (array_to_integer (input->Type, 2)) {
+    
+        case IMAGE_REL_I386_ABSOLUTE:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_IGNORED];
+            break;
+        
+        case IMAGE_REL_I386_DIR16:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_16];
+            break;
+        
+        case IMAGE_REL_I386_DIR32:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_32];
+            break;
+        
+        case IMAGE_REL_I386_DIR32NB:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_32_NO_BASE];
+            break;
+        
+        case IMAGE_REL_I386_REL16:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_PC16];
+            break;
+        
+        case IMAGE_REL_I386_REL32:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+            break;
+    
+    }
+
+}
+
+static unsigned long translate_Characteristics_to_alignment (unsigned long Characteristics) {
+
+    unsigned long alignment = 1;
+    Characteristics &= IMAGE_SCN_ALIGN_8192BYTES;
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_1BYTES) {
+        alignment = 1;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_2BYTES) {
+        alignment = 2;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_4BYTES) {
+        alignment = 4;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_8BYTES) {
+        alignment = 8;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_16BYTES) {
+        alignment = 16;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_32BYTES) {
+        alignment = 32;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_64BYTES) {
+        alignment = 64;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_128BYTES) {
+        alignment = 128;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_256BYTES) {
+        alignment = 256;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_512BYTES) {
+        alignment = 512;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_1024BYTES) {
+        alignment = 1024;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_2048BYTES) {
+        alignment = 2048;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_4096BYTES) {
+        alignment = 4096;
+    }
+    
+    if (Characteristics == IMAGE_SCN_ALIGN_8192BYTES) {
+        alignment = 8192;
+    }
+    
+    return alignment;
+
+}
+
+static unsigned long translate_Characteristics_to_section_flags (unsigned long Characteristics) {
+
+    unsigned long flags = 0;
+    
+    if (!(Characteristics & IMAGE_SCN_MEM_WRITE)) {
+        flags |= SECTION_FLAG_READONLY;
+    }
+    
+    if (Characteristics & (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE)) {
+        flags |= SECTION_FLAG_CODE;
+    }
+    
+    if (Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
+        flags |= SECTION_FLAG_DATA;
+    }
+    
+    if (Characteristics & IMAGE_SCN_TYPE_NOLOAD) {
+        flags |= SECTION_FLAG_NEVER_LOAD;
+    }
+    
+    if (Characteristics & IMAGE_SCN_LNK_INFO) {
+        flags |= SECTION_FLAG_DEBUGGING;
+    }
+    
+    if (Characteristics & IMAGE_SCN_LNK_REMOVE) {
+        flags |= SECTION_FLAG_EXCLUDE;
+    }
+    
+    if (!(Characteristics & IMAGE_SCN_MEM_READ)) {
+        flags |= SECTION_FLAG_NOREAD;
+    }
+    
+    if (Characteristics & IMAGE_SCN_MEM_SHARED) {
+        flags |= SECTION_FLAG_SHARED;
+    }
+    
+    if (Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
+        flags |= SECTION_FLAG_ALLOC;
+    }
+    
+    return flags;
+
+}
+
+#define     IMAGE_SYM_DEBUG             -2
+
+#define     IMAGE_SYM_UNDEFINED         0
+#define     IMAGE_SYM_CLASS_EXTERNAL    2
+
+void read_coff_object (const char *filename, unsigned char *data, unsigned long data_size) {
+
+    struct coff_header *coff_hdr;
+    struct coff_relocation_entry *reloc_info;
+    
+    struct coff_section_table_entry *section_hdr;
+    struct string_table_header *string_table_hdr;
+    
+    struct section_part **part_p_array, *part;
+    struct object_file *of;
+    
+    struct section *section;
+    struct subsection *subsection;
+    
+    char *string_table = 0, *section_name, *p;
+    unsigned long string_table_size, no_sections, no_syms;
+    
+    unsigned char *pos = (unsigned char *) data;
+    unsigned long i;
+    
+    struct section_part *bss_part = 0;
+    long bss_section_number;
+    
+    if ((pos - data + sizeof (*coff_hdr) > data_size) || pos < data) {
+    
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: corrupted input file", filename);
+        return;
+    
+    }
+    
+    coff_hdr = (struct coff_header *) data;
+    
+    pos = (unsigned char *) data + array_to_integer (coff_hdr->PointerToSymbolTable, 4) + sizeof (struct symbol_table_entry) * array_to_integer (coff_hdr->NumberOfSymbols, 4);
+    string_table_hdr = (struct string_table_header *) pos;
+    
+    if ((string_table_size = array_to_integer (string_table_hdr->StringTableSize, 4)) < 4) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: invalid string table size: %lu", filename, string_table_size);
+        return;
+    
+    }
+    
+    string_table = (char *) pos;
+    
+    part_p_array = xmalloc (sizeof (*part_p_array) * (array_to_integer (coff_hdr->NumberOfSections, 2) + 1));
+    of = object_file_make (filename, array_to_integer (coff_hdr->NumberOfSymbols, 4));
+    
+    no_sections = array_to_integer (coff_hdr->NumberOfSections, 2);
+    
+    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_name = xstrndup (section_hdr->Name, 8);
+        
+        if (section_name[0] == '/') {
+        
+            unsigned long offset = strtoul (section_name + 1, NULL, 10);
+            
+            if (offset < array_to_integer (string_table_hdr->StringTableSize, 4)) {
+            
+                free (section_name);
+                section_name = xstrdup (string_table + offset);
+            
+            } else {
+                report_at (program_name, 0, REPORT_ERROR, "%s: invalid offset into string table", filename);
+            }
+        
+        }
+        
+        if ((p = strchr (section_name, '$'))) {
+            *p++ = '\0';
+        }
+        
+        section = section_find_or_make (section_name);
+        section->flags = translate_Characteristics_to_section_flags (array_to_integer (section_hdr->Characteristics, 4));
+        
+        if (array_to_integer (section_hdr->PointerToRawData, 4) == 0 && array_to_integer (section_hdr->SizeOfRawData, 4)) {
+            section->is_bss = 1;
+        }
+        
+        subsection = (p ? subsection_find_or_make (section, p) : 0);
+        free (section_name);
+        
+        part = section_part_new (section, of);
+        part->alignment = translate_Characteristics_to_alignment (array_to_integer (section_hdr->Characteristics, 4));
+        part->content_size = array_to_integer (section_hdr->SizeOfRawData, 4);
+        
+        if (array_to_integer (section_hdr->PointerToRawData, 4)) {
+        
+            pos = (unsigned char *) data + array_to_integer (section_hdr->PointerToRawData, 4);
+            
+            part->content = xmalloc (part->content_size);
+            memcpy (part->content, pos, part->content_size);
+        
+        }
+        
+        if (array_to_integer (section_hdr->PointerToRelocations, 4) && array_to_integer (section_hdr->NumberOfRelocations, 2)) {
+        
+            unsigned long j, no_relocs;
+            
+            if (!array_to_integer (section_hdr->PointerToRawData, 4)) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: section '%s' is BSS but has relocations", filename, section->name);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            pos = (unsigned char *) data + array_to_integer (section_hdr->PointerToRelocations, 4);
+            
+            part->reloc_arr = xmalloc (sizeof (struct reloc_entry) * array_to_integer (section_hdr->NumberOfRelocations, 2));
+            part->reloc_cnt = array_to_integer (section_hdr->NumberOfRelocations, 2);
+            
+            no_relocs = array_to_integer (section_hdr->NumberOfRelocations, 2);
+            
+            for (j = 0; j < no_relocs; j++) {
+            
+                reloc_info = (struct coff_relocation_entry *) (pos + (sizeof (*reloc_info) * j));
+                translate_relocation (part->reloc_arr + j, reloc_info, part);
+            
+            }
+        
+        }
+        
+        if (subsection) {
+            subsection_append_section_part (subsection, part);
+        } else {
+            section_append_section_part (section, part);
+        }
+        
+        part_p_array[i + 1] = part;
+    
+    }
+    
+    no_syms = array_to_integer (coff_hdr->NumberOfSymbols, 4);
+    
+    for (i = 0; i < no_syms; i++) {
+    
+        struct symbol_table_entry *coff_symbol;
+        struct symbol *symbol = of->symbol_arr + i;
+        
+        int 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) {
+        
+            unsigned long offset = array_to_integer (coff_symbol->Name + 4, 4);
+            
+            if (offset < array_to_integer (string_table_hdr->StringTableSize, 4)) {
+                symbol->name = xstrdup (string_table + offset);
+            } else {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid offset into string table", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        } else {
+            symbol->name = xstrndup ((char *) coff_symbol->Name, 8);
+        }
+        
+        symbol->value = array_to_integer (coff_symbol->value, 4);
+        symbol->section_number = array_to_integer (coff_symbol->SectionNumber, 2);
+        
+        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 (symbol->value) {
+            
+                if (!bss_part) {
+                
+                    struct section *section = section_find_or_make (".bss");
+                    
+                    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_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;
+                    
+                    section_append_section_part (section, bss_part);
+                
+                }
+                
+                bss_part->content_size += symbol->value;
+                symbol->part = bss_part;
+                
+                symbol->value = bss_part->content_size - symbol->value;
+                symbol->section_number = bss_section_number;
+            
+            } else {
+                symbol->part = 0;
+            }
+        
+        } 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) {
+            symbol->part = 0;
+        } else if (section_no > no_sections) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "%s: invalid symbol SectionNumber: %hi", filename, section_no);
+            symbol->part = 0;
+        
+        } else {
+        
+            report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++not yet supported symbol SectionNumber: %hi", section_no);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        symbol->section_number = section_no;
+        
+        if (coff_symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
+            symbol_record_external_symbol (symbol);
+        }
+        
+        if (coff_symbol->NumberOfAuxSymbols) {
+        
+            for (i++; coff_symbol->NumberOfAuxSymbols; coff_symbol->NumberOfAuxSymbols--) {
+            
+                symbol = of->symbol_arr + i;
+                
+                memset (symbol, 0, sizeof (*symbol));
+                symbol->auxiliary = 1;
+            
+            }
+        
+        }
+    
+    }
+    
+    free (part_p_array);
+
+}
+
+
 struct exclude_symbol {
 
     char *name;
diff --git a/coff.h b/coff.h
index 1c826aeb44f0c5f4d0da32013cadbcba7fa7902d..8aa5fc009e975c3876eab5bf94c28342881a0cfc 100644 (file)
--- a/coff.h
+++ b/coff.h
@@ -71,7 +71,20 @@ struct coff_section_table_entry {
 #define     IMAGE_SCN_CNT_UNINITIALIZED_DATA                0x00000080
 #define     IMAGE_SCN_LNK_INFO                              0x00000200
 #define     IMAGE_SCN_LNK_REMOVE                            0x00000800
+#define     IMAGE_SCN_ALIGN_1BYTES                          0x00100000
+#define     IMAGE_SCN_ALIGN_2BYTES                          0x00200000
 #define     IMAGE_SCN_ALIGN_4BYTES                          0x00300000
+#define     IMAGE_SCN_ALIGN_8BYTES                          0x00400000
+#define     IMAGE_SCN_ALIGN_16BYTES                         0x00500000
+#define     IMAGE_SCN_ALIGN_32BYTES                         0x00600000
+#define     IMAGE_SCN_ALIGN_64BYTES                         0x00700000
+#define     IMAGE_SCN_ALIGN_128BYTES                        0x00800000
+#define     IMAGE_SCN_ALIGN_256BYTES                        0x00900000
+#define     IMAGE_SCN_ALIGN_512BYTES                        0x00A00000
+#define     IMAGE_SCN_ALIGN_1024BYTES                       0x00B00000
+#define     IMAGE_SCN_ALIGN_2048BYTES                       0x00C00000
+#define     IMAGE_SCN_ALIGN_4096BYTES                       0x00D00000
+#define     IMAGE_SCN_ALIGN_8192BYTES                       0x00E00000
 #define     IMAGE_SCN_MEM_SHARED                            0x10000000
 #define     IMAGE_SCN_MEM_EXECUTE                           0x20000000
 #define     IMAGE_SCN_MEM_READ                              0x40000000
@@ -93,6 +106,8 @@ struct coff_relocation_entry {
 #define     IMAGE_REL_I386_DIR32NB                          0x0007
 #define     IMAGE_REL_I386_REL32                            0x0014
 
+void read_coff_object (const char *filename, unsigned char *data, unsigned long data_size);
+
 void coff_after_link (void);
 void coff_before_link (void);
 
diff --git a/ld.c b/ld.c
index 9c3d68e7872413be4505b98f63269c2834a43a8c..c67812055bc94e8b0b441081453f8fcded41a3a6 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -69,12 +69,15 @@ static int read_file_into_memory (const char *filename, unsigned char **memory_p
 
 static void read_object_file (const char *filename, unsigned char *data, unsigned long data_size) {
 
+    /*report_at (program_name, 0, REPORT_ERROR, "%s: signature: %#x:%#x", filename, data[0], data[1]);*/
     /*printf ("reading: %s\n", filename);*/
     
     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 if (data[0] == 0x4C && data[1] == 0x01) {
+        read_coff_object (filename, data, data_size);
     } else if (data[0] == RECORD_TYPE_THEADR) {
         read_omf_object (filename, data, data_size);
     } else {
@@ -155,6 +158,16 @@ static void read_archive (const char *filename, unsigned char *data) {
             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);
             
@@ -262,6 +275,8 @@ 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/omf.c b/omf.c
index cb3cdf1648a645377deac4749d7ad7d7948afc56..8d8956230d8b1a90c70427a072d56fe9bdf953dd 100644 (file)
--- a/omf.c
+++ b/omf.c
@@ -16,6 +16,7 @@
 static void estimate (void *data, unsigned long data_size, const char *filename, unsigned long *num_segments_p, unsigned long *num_extdefs_p, unsigned long *num_pubdefs_p, unsigned long *num_lnames_p) {
 
     unsigned char *pos = (unsigned char *) data;
+    unsigned char base_segment_index;
     
     unsigned char record_type;
     unsigned short record_len;
@@ -80,20 +81,31 @@ static void estimate (void *data, unsigned long data_size, const char *filename,
         
         } else if (record_type == RECORD_TYPE_PUBDEF) {
         
-            pubdef_name_end = (pubdef_name = pos) + record_len - 3;
+            unsigned long prefix = 1;
+            unsigned long suffix = 2 + 1;
+            
+            pubdef_name_end = pos + record_len - 1;
             
             if (big_fields) {
+                suffix += 2;
+            }
             
-                report_at (program_name, 0, REPORT_INTERNAL_ERROR, "%s: big fields not supported for record %#x", filename, record_type);
-                exit (EXIT_FAILURE);
+            base_segment_index = pos[1];
+            
+            if (!base_segment_index) {
+            
+                report_at (program_name, 0, REPORT_WARNING, "%s: PUBDEF Base Frame is not supported", filename);
+                prefix += 2;
             
             }
             
+            pubdef_name = pos + 2;
+            
             while (pubdef_name != pubdef_name_end) {
             
-                pubdef_name_len = pubdef_name[2];
+                pubdef_name_len = pubdef_name[prefix - 1];
                 
-                if (pubdef_name + 2 + 1 + pubdef_name_len + 1 > pubdef_name_end) {
+                if (pubdef_name + prefix + pubdef_name_len + suffix > pubdef_name_end) {
                 
                     report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: incorrect pubdef string length", filename);
                     exit (EXIT_FAILURE);
@@ -101,7 +113,7 @@ static void estimate (void *data, unsigned long data_size, const char *filename,
                 }
                 
                 num_pubdefs++;
-                pubdef_name = pubdef_name + 2 + 1 + pubdef_name_len + 1;
+                pubdef_name = pubdef_name + prefix + pubdef_name_len + suffix;
             
             }
         
@@ -249,30 +261,45 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
         
         } else if (record_type == RECORD_TYPE_PUBDEF) {
         
-            pubdef_name_end = (pubdef_name = pos) + record_len - 3;
-            base_segment_index = pubdef_name[1];
+            unsigned long prefix = 1;
+            unsigned long suffix = 2 + 1;
             
-            while (pubdef_name != pubdef_name_end) {
+            pubdef_name_end = pos + record_len - 1;
             
-                pubdef_name_len = pubdef_name[2];
-                
-                public_offset = array_to_integer (pubdef_name + 3 + pubdef_name_len, 2);
-                symbol = of->symbol_arr + i_extdefs++;
-                
-                if (base_segment_index >= i_segments || !base_segment_index) {
+            if (big_fields) {
+                suffix += 2;
+            }
             
-                    report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid base segment index %d", filename, base_segment_index);
-                    exit (EXIT_FAILURE);
+            base_segment_index = pos[1];
+            
+            if (!base_segment_index) {
+            
+                report_at (program_name, 0, REPORT_WARNING, "%s: PUBDEF Base Frame is not supported", filename);
+                prefix += 2;
+            
+            }
+            
+            pubdef_name = pos + 2;
+            
+            while (pubdef_name != pubdef_name_end) {
+            
+                pubdef_name_len = pubdef_name[prefix - 1];
                 
+                if (big_fields) {
+                    public_offset = array_to_integer (pubdef_name + prefix + pubdef_name_len, 4);
+                } else {
+                    public_offset = array_to_integer (pubdef_name + prefix + pubdef_name_len, 2);
                 }
                 
-                symbol->name = xstrndup ((char *) pubdef_name + 3, pubdef_name_len);
+                symbol = of->symbol_arr + i_pubdefs++;
+                
+                symbol->name = xstrndup ((char *) pubdef_name + prefix, pubdef_name_len);
                 symbol->value = public_offset;
                 symbol->part = part_p_array[base_segment_index];
                 symbol->section_number = base_segment_index;
                 
                 symbol_record_external_symbol (symbol);
-                pubdef_name = pubdef_name + 2 + 1 + pubdef_name_len + 1;
+                pubdef_name = pubdef_name + prefix + pubdef_name_len + suffix;
             
             }
         
@@ -298,13 +325,6 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
             
             unsigned long segment_len;
             
-            if (!(attributes & SEGMENT_ATTR_P)) {
-            
-                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: OMF USE16 segments are not supported", filename);
-                exit (EXIT_FAILURE);
-            
-            }
-            
             if ((attributes >> 5) == 0) {
             
                 report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: OMF absolute segments are not supported", filename);
@@ -321,19 +341,21 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
             
             } else {
             
-                report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: non big fields not supported for record %#x", filename, record_type);
-                exit (EXIT_FAILURE);
+                segment_len = array_to_integer (pos + 1, 2);
+                
+                segment_name_index = pos[3];
+                class_name_index = pos[4];
             
             }
             
-            if (segment_name_index >= i_lnames  || !segment_name_index) {
+            if (segment_name_index >= i_lnames || !segment_name_index) {
             
                 report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid segment name index", filename);
                 exit (EXIT_FAILURE);
             
             }
             
-            if (class_name_index >= i_lnames  || !class_name_index) {
+            if (class_name_index >= i_lnames || !class_name_index) {
             
                 report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid class name index", filename);
                 exit (EXIT_FAILURE);
@@ -415,13 +437,6 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
             
             }
             
-            if (!big_fields) {
-            
-                report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: non big field not supported for record %#x", filename, record_type);
-                exit (EXIT_FAILURE);
-            
-            }
-            
             while (subrec != end) {
             
                 if (subrec[0] & 0x80) {
@@ -432,16 +447,19 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
                     unsigned char fixdat, frame_method, target_method;
                     unsigned short data_record_offset, target_datum;
                     
-                    if (subrec[0] & 0x40) {
-                    
-                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only self-relative OMF fixups are supported", filename);
-                        exit (EXIT_FAILURE);
+                    unsigned char loc;
+                    int bits;
                     
-                    }
+                    /*seg_reloc = subrec[0] & 0x40;*/
+                    loc = subrec[0] >> 2;
                     
-                    if (((subrec[0] >> 2) & 0x0f) != 9) {
+                    if ((loc & 0x0F) == 1) {
+                        bits = 16;
+                    } else if ((loc & 0x0F) == 9) {
+                        bits = 32;
+                    } else {
                     
-                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only 32-bit offset OMF fixups are supported", filename);
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only 16-bit/32-bit offset OMF fixups are supported", filename);
                         exit (EXIT_FAILURE);
                     
                     }
@@ -521,7 +539,12 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
                     
                     reloc->offset = data_record_offset;
                     reloc->addend = 0;
-                    reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+                    
+                    if (bits == 16) {
+                        reloc->howto = &reloc_howtos[RELOC_TYPE_PC16];
+                    } else {
+                        reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+                    }
                     
                     subrec += 4;
                 
@@ -546,12 +569,14 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d
             if (big_fields) {
             
                 offset = array_to_integer (pos + 1, 4);
+                
                 size = record_len - 6;
                 data_bytes = pos + 5;
             
             } else {
             
                 offset = array_to_integer (pos + 1, 2);
+                
                 size = record_len - 4;
                 data_bytes = pos + 3;
             
diff --git a/omf.h b/omf.h
index b8bfef346f863ee23e0503950123ba6ff02dcfbd..292f16b9605f90e59e434151c782e8aa48e54b7a 100644 (file)
--- a/omf.h
+++ b/omf.h
 #define     RECORD_TYPE_FIXUPP          0x9C
 #define     RECORD_TYPE_LEDATA          0xA0
 
-#define     SEGMENT_ATTR_P              0x1
+#define     SEGMENT_ATTR_P              0x01
 
-#define     METHOD_T2_EXTDEF            2
-#define     METHOD_F5                   5
+#define     METHOD_T2_EXTDEF            0x02
+#define     METHOD_F5                   0x05
 
 void read_omf_object (const char *filename, unsigned char *data, unsigned long data_size);
 
diff --git a/pe.c b/pe.c
index 16bbc1a96e9267bc904059718446adaa26611b02..0efc358170d8a7c006d80e08e31d64ea899fb646 100644 (file)
--- a/pe.c
+++ b/pe.c
@@ -363,6 +363,10 @@ static void generate_base_relocation_block (struct section *reloc_section, struc
                     continue;
                 }
                 
+                if (part->rva + relocs[i].offset < array_to_integer (ibr_hdr_p->RVAOfBlock, 4)) {
+                    continue;
+                }
+                
                 rel_word  = (part->rva + relocs[i].offset - array_to_integer (ibr_hdr_p->RVAOfBlock, 4)) & 0xfff;
                 rel_word |= base_relocation_type << 12;
                 
@@ -699,6 +703,7 @@ void pe_write (const char *filename) {
     struct pe_optional_header *opthdr;
     
     struct section *section;
+    unsigned long size_of_optional_header;
     
     if (!(fp = fopen (filename, "wb"))) {
     
@@ -721,9 +726,10 @@ void pe_write (const char *filename) {
     write_sections (data);
     
     doshdr = (struct msdos_header *) data;
-    pehdr = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub));
     
+    pehdr = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub));
     opthdr = (struct pe_optional_header *) ((char *) pehdr + sizeof (*pehdr));
+    
     pos = (unsigned char *) opthdr + sizeof (*opthdr);
     
     doshdr->e_magic[0] = 'M';
@@ -749,7 +755,10 @@ void pe_write (const char *filename) {
     write721_to_byte_array (pehdr->Machine, IMAGE_FILE_MACHINE_I386);
     write721_to_byte_array (pehdr->NumberOfSections, section_count ());
     write741_to_byte_array (pehdr->TimeDateStamp, time (0));
-    write721_to_byte_array (pehdr->SizeOfOptionalHeader, sizeof (*opthdr));
+    
+    size_of_optional_header = sizeof (*opthdr);
+    size_of_optional_header += NUMBER_OF_DATA_DIRECTORIES * sizeof (struct pe_image_data_directory);
+    write721_to_byte_array (pehdr->SizeOfOptionalHeader, size_of_optional_header);
     
     {
     
@@ -796,12 +805,24 @@ void pe_write (const char *filename) {
     if (last_section) {
         write741_to_byte_array (opthdr->SizeOfImage, ALIGN (last_section->rva + last_section->total_size, section_alignment));
     } else {
-        write741_to_byte_array (opthdr->SizeOfImage, state->size_of_headers);
+        write741_to_byte_array (opthdr->SizeOfImage, ALIGN (state->size_of_headers, section_alignment));
     }
     
     write741_to_byte_array (opthdr->SizeOfHeaders, state->size_of_headers);
     write721_to_byte_array (opthdr->Subsystem, subsystem);
     
+    {
+    
+        unsigned short characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
+        
+        if (can_be_relocated) {
+            characteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
+        }
+        
+        write721_to_byte_array (opthdr->DllCharacteristics, characteristics);
+    
+    }
+    
     {
     
         struct section *bss_section;
@@ -833,6 +854,74 @@ void pe_write (const char *filename) {
     write741_to_byte_array (opthdr->NumberOfRvaAndSizes, NUMBER_OF_DATA_DIRECTORIES);
     
     
+    {
+    
+        struct pe_image_data_directory *idd;
+        int i;
+        
+        for (i = 0; i < NUMBER_OF_DATA_DIRECTORIES; i++) {
+        
+            idd = (struct pe_image_data_directory *) pos;
+            
+            switch (i) {
+            
+                case 0:
+                
+                    /* EXPORT Table. */
+                    if ((section = section_find (".edata"))) {
+                    
+                        write741_to_byte_array (idd->VirtualAddress, section->rva);
+                        write741_to_byte_array (idd->Size, section->total_size);
+                    
+                    }
+                    
+                    break;
+                
+                case 1:
+                
+                    /* IMPORT Table. */
+                    if ((section = section_find (".idata"))) {
+                    
+                        write741_to_byte_array (idd->VirtualAddress, section->rva);
+                        write741_to_byte_array (idd->Size, section->total_size);
+                    
+                    }
+                    
+                    break;
+                
+                case 5:
+                
+                    /* BASE RELOCATION Table. */
+                    if ((section = section_find (".reloc"))) {
+                    
+                        write741_to_byte_array (idd->VirtualAddress, section->rva);
+                        write741_to_byte_array (idd->Size, section->total_size);
+                    
+                    }
+                    
+                    break;
+                
+                case 12:
+                
+                    /* IMPORT Address Table. */
+                    if ((section = section_find (".idata"))) {
+                    
+                        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);
+                    
+                    }
+                    
+                    break;
+            
+            }
+            
+            pos += sizeof (*idd);
+        
+        }
+    
+    }
+    
+    
     for (section = all_sections; section; section = section->next) {
     
         struct pe_section_table_entry *hdr = section->object_dependent_data;
diff --git a/pe.h b/pe.h
index f20994259b07ab278dd2a8371c51835f7365b545..758acdb6b748ba19f89230e525d6ebba7894d0b5 100644 (file)
--- a/pe.h
+++ b/pe.h
@@ -44,6 +44,9 @@ struct msdos_header {
 #define     IMAGE_SUBSYSTEM_XBOX                            14
 #define     IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPILCATION        16
 
+#define     IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE           0x0040
+#define     IMAGE_DLLCHARACTERISTICS_NX_COMPAT              0x0100
+
 struct pe_header {
 
     unsigned char Signature[4];
@@ -112,10 +115,6 @@ struct pe_optional_header {
     
     unsigned char LoaderFlags[4];
     unsigned char NumberOfRvaAndSizes[4];
-    
-    
-    /*unsigned char Reserved[128];*/
-    unsigned char Reserved[32 * 4];
 
 };
 
diff --git a/reloc.h b/reloc.h
index a4bb555abae01243475bc31a59ca2ea637678fc3..f5e64626a4df4e4c26940c599735f7f144098a40 100644 (file)
--- a/reloc.h
+++ b/reloc.h
@@ -20,6 +20,7 @@ enum {
     RELOC_TYPE_8,
     RELOC_TYPE_PC8,
     
+    RELOC_TYPE_32_NO_BASE,
     RELOC_TYPE_END
 
 };
index c4e2c32baab04c8c547568d4d746acd9b9c106e0..2c9dcbf83c698ca4fc5b9bb02e1f7322cb3d4906 100644 (file)
--- a/section.c
+++ b/section.c
@@ -180,6 +180,34 @@ struct subsection *subsection_find (struct section *section, const char *name) {
 
 }
 
+struct subsection *subsection_find_or_make (struct section *section, const char *name) {
+
+    struct subsection *subsection, **next_p;
+    
+    for (subsection = *(next_p = &section->all_subsections); subsection; subsection = *(next_p = &subsection->next)) {
+    
+        if (strcmp (name, subsection->name) <= 0) {
+            break;
+        }
+    
+    }
+    
+    if (!subsection || strcmp (name, subsection->name) != 0) {
+    
+        subsection = xmalloc (sizeof (*subsection));
+        
+        subsection->name = xstrdup (name);
+        subsection->next = *next_p;
+        subsection->last_part_p = &subsection->first_part;
+        
+        *next_p = subsection;
+    
+    }
+    
+    return subsection;
+
+}
+
 void subsection_append_section_part (struct subsection *subsection, struct section_part *part) {
 
     *subsection->last_part_p = part;
index 0f0686ba7d3f82f262fc02b1bb4b82afa334a6e0..1c4f4698da8755cdab52f0dc1217ba2f1ccbec24 100644 (file)
--- a/section.h
+++ b/section.h
@@ -99,6 +99,8 @@ void section_write (struct section *section, unsigned char *memory);
 int section_count (void);
 
 struct subsection *subsection_find (struct section *section, const char *name);
+struct subsection *subsection_find_or_make (struct section *section, const char *name);
+
 void subsection_append_section_part (struct subsection *subsection, struct section_part *part);
 
 #endif      /* _SECTION_H */