Added support for short import library entries
authorRobert Pengelly <robertapengelly@hotmail.com>
Sun, 4 May 2025 16:45:58 +0000 (17:45 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Sun, 4 May 2025 16:45:58 +0000 (17:45 +0100)
coff.c
ld.c
pe.c
pe.h

diff --git a/coff.c b/coff.c
index 89aa544b17ab135de7a30f914f0c43bbf8ac4e85..4da89bdfa9d3ce8937d03eb0735466f4e83cf1e8 100644 (file)
--- a/coff.c
+++ b/coff.c
@@ -190,10 +190,10 @@ static unsigned long translate_Characteristics_to_section_flags (unsigned long C
 
 }
 
+#define     IMAGE_SYM_ABSOLUTE          -1
 #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) {
@@ -351,15 +351,15 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
         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;
         
+        struct symbol_table_entry *coff_symbol;
         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) {
@@ -395,7 +395,7 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
                 
                 if (!old_symbol || symbol_is_undefined (old_symbol)) {
                 
-                    if (bss_section) {
+                    if (!bss_section) {
                     
                         bss_section = section_find_or_make (".bss");
                         
diff --git a/ld.c b/ld.c
index 7a22f160c64210661af28a1edf70c1d9e335e075..c65a572e79a53033714db1028c19184e92dc7f6c 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -93,6 +93,17 @@ static int read_object_file (const char *filename, unsigned char *data, unsigned
     
     }
     
+    if (data[0] == 0 && data[1] == 0) {
+    
+        if (data[2] == 0xff && data[3] == 0xff) {
+        
+            read_pe_import_library (filename, data);
+            return 0;
+        
+        }
+    
+    }
+    
     if (data[0] == RECORD_TYPE_THEADR) {
     
         read_omf_object (filename, data, data_size);
@@ -205,20 +216,26 @@ static void read_archive (const char *filename, unsigned char *data) {
     
     }
     
-    for (i = 0; i < no_symbols && (!start_header_object_offset || !end_header_object_offset); i++) {
+    if (state->format == LD_FORMAT_I386_PE) {
     
-        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;
+        for (i = 0; i < no_symbols && (!start_header_object_offset || !end_header_object_offset); i++) {
+        
+            char *symbol_name = offset_name_table[i].name;
+            
+            if (strncmp (symbol_name, "__head_", 7) == 0) {
+                start_header_object_offset = offset_name_table[i].offset;
+            } else if (strlen (symbol_name) > 6 && strncmp (symbol_name + strlen (symbol_name) - 6, "_iname", 6) == 0) {
+                end_header_object_offset = offset_name_table[i].offset;
+            }
+        
+        }
+        
+        if (start_header_object_offset) {
+            read_archive_memeber (data + start_header_object_offset, filename);
         }
     
     }
     
-    if (start_header_object_offset) {
-        read_archive_memeber (data + start_header_object_offset, filename);
-    }
-    
     while (1) {
     
         struct symbol *symbol;
@@ -246,8 +263,14 @@ static void read_archive (const char *filename, unsigned char *data) {
     
     }
     
-    if (end_header_object_offset) {
-        read_archive_memeber (data + end_header_object_offset, filename);
+    if (state->format == LD_FORMAT_I386_PE) {
+    
+        if (end_header_object_offset) {
+            read_archive_memeber (data + end_header_object_offset, filename);
+        }
+        
+        pe_archive_end ();
+    
     }
     
     free (offset_name_table);
diff --git a/pe.c b/pe.c
index 59c874037182c86ba142b5485da057623b0f2199..668008a5664601f1a8c7e1a985faad830cc600a5 100644 (file)
--- a/pe.c
+++ b/pe.c
@@ -955,3 +955,362 @@ unsigned long pe_get_first_section_rva (void) {
 unsigned long pe_align_to_file_alignment (unsigned long value) {
     return ALIGN (value, file_alignment);
 }
+
+struct import_library_header {
+
+    unsigned char Magic1[2];
+    unsigned char Magic2[2];
+    unsigned char Version[2];
+    unsigned char Machine[2];
+    unsigned char TimeDateStamp[4];
+    unsigned char SizeOfData[4];
+    unsigned char OrdinalHint[2];
+    unsigned char Type[2];
+
+};
+
+#define     IMPORT_CODE                 0
+#define     IMPORT_DATA                 1
+#define     IMPORT_CONST                2
+
+#define     IMPORT_ORDINAL              0
+#define     IMPORT_NAME                 1
+#define     IMPORT_NAME_NOPREFIX        2
+#define     IMPORT_NAME_UNDECORATE      3
+
+static char *unprefix_name (const char *orig_name) {
+    return (orig_name[0] == '_' ? xstrdup (orig_name + 1) : xstrdup (orig_name));
+}
+
+static char *undecorate_name (const char *orig_name) {
+
+    char *at_p;
+    
+    if (orig_name[0] == '_') {
+        orig_name++;
+    }
+    
+    if ((at_p = strchr (orig_name, '@'))) {
+        return xstrndup (orig_name, at_p - orig_name);
+    }
+    
+    return xstrdup (orig_name);
+
+}
+
+static void import_generate_import (const char *import_name, short ordinal_hint, short import_type, short import_name_type, const char *filename) {
+
+    struct object_file *of;
+    struct symbol *symbol;
+    
+    struct section_part *part;
+    struct section *section;
+    
+    struct reloc_entry *relocs;
+    struct subsection *subsection;
+    
+    struct section_part *dot_idata5_part;
+    char *real_import_name;
+    
+    of = object_file_make (filename, 2 + 1 + ((import_type == IMPORT_CODE) ? 1 : 0));
+    symbol = of->symbol_arr;
+    
+    section = section_find_or_make (".idata");
+    subsection = subsection_find_or_make (section, "4");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content = xmalloc (part->content_size = 4);
+    part->reloc_cnt = 1;
+    part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
+    
+    relocs = part->reloc_arr;
+    
+    relocs[0].symbol = &of->symbol_arr[1];
+    relocs[0].howto = &reloc_howtos[RELOC_TYPE_32_NO_BASE];
+    relocs[0].offset = 0;
+    
+    subsection = subsection_find_or_make (section, "5");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content = xmalloc (part->content_size = 4);
+    
+    symbol->name = xstrdup (".idata$5");
+    symbol->value = 0;
+    symbol->part = part;
+    symbol->section_number = 2;
+    
+    symbol++;
+    
+    part->reloc_cnt = 1;
+    part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
+    
+    relocs = part->reloc_arr;
+    
+    relocs[0].symbol = &of->symbol_arr[1];
+    relocs[0].howto = &reloc_howtos[RELOC_TYPE_32_NO_BASE];
+    relocs[0].offset = 0;
+    
+    dot_idata5_part = part;
+    subsection = subsection_find_or_make (section, "6");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    switch (import_name_type) {
+    
+        case IMPORT_ORDINAL:
+        
+            report_at (program_name, 0, REPORT_INTERNAL_ERROR, "IMPORT_ORDINAL is not yet supported");
+            exit (EXIT_FAILURE);
+        
+        case IMPORT_NAME:
+        
+            real_import_name = xstrdup (import_name);
+            break;
+        
+        case IMPORT_NAME_NOPREFIX:
+        
+            real_import_name = unprefix_name (import_name);
+            break;
+        
+        case IMPORT_NAME_UNDECORATE:
+        
+            real_import_name = undecorate_name (import_name);
+            break;
+        
+        default:
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "invalid or unsupported ImportNameType: %i", import_name_type);
+            exit (EXIT_FAILURE);
+    
+    }
+    
+    part->content = xmalloc (part->content_size = ALIGN (2 + strlen (real_import_name) + 1, 2));
+    
+    integer_to_array (ordinal_hint, part->content, 2);
+    strcpy ((char *) part->content + 2, real_import_name);
+    
+    free (real_import_name);
+    
+    symbol->name = xstrdup (".idata$6");
+    symbol->value = 0;
+    symbol->part = part;
+    symbol->section_number = 3;
+    
+    symbol++;
+    
+    if (import_type == IMPORT_CODE) {
+    
+        section = section_find_or_make (".text");
+        
+        part = section_part_new (section, of);
+        section_append_section_part (section, part);
+        
+        part->content = xmalloc (part->content_size = 8);
+        memcpy (part->content, "\xFF\x25\x00\x00\x00\x00\x90\x90", 8);
+        
+        symbol->name = xstrdup (import_name);
+        symbol->value = 0;
+        symbol->part = part;
+        symbol->section_number = 4;
+        symbol_record_external_symbol (symbol);
+        
+        symbol++;
+        
+        part->reloc_cnt = 1;
+        part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
+        
+        relocs = part->reloc_arr;
+        
+        relocs[0].symbol = &of->symbol_arr[0];
+        relocs[0].howto = &reloc_howtos[RELOC_TYPE_32];
+        relocs[0].offset = 2;
+    
+    }
+    
+    symbol->name = xmalloc (6 + strlen (import_name) + 1);
+    sprintf (symbol->name, "__imp_%s", import_name);
+    
+    symbol->value = 0;
+    symbol->part = dot_idata5_part;
+    symbol->section_number = 2;
+    symbol_record_external_symbol (symbol);
+
+}
+
+
+/**
+ * According to https://oldweb.today/?browser=ff10#19831010000000/http://learn.microsoft.com/en-us/windows/win32/debug/pe-format
+ * the short form entries have had the dll name in the entry since dll's were introduced in 1983 so it should be safe to assume
+ * that there's one present.
+ */
+char *current_import_dll_name = 0;
+
+static void import_generate_head (const char *filename, const char *dll_name) {
+
+    struct object_file *of;
+    struct subsection *subsection;
+    
+    struct section *section;
+    struct section_part *part;
+    
+    struct pe_import_directory_table *import_dt;
+    struct reloc_entry *relocs;
+    
+    unsigned long i;
+    of = object_file_make (filename, 3);
+    
+    section = section_find_or_make (".idata");
+    section->flags = translate_characteristics_to_section_flags (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE);
+    
+    subsection = subsection_find_or_make (section, "2");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    import_dt = (struct pe_import_directory_table *) (part->content = xmalloc (part->content_size = sizeof (*import_dt)));
+    
+    integer_to_array (0, import_dt->ImportNameTableRVA, 4);
+    integer_to_array (0, import_dt->TimeDateStamp, 4);
+    integer_to_array (0, import_dt->ForwarderChain, 4);
+    integer_to_array (0, import_dt->NameRVA, 4);
+    integer_to_array (0, import_dt->ImportAddressTableRVA, 4);
+    
+    part->reloc_cnt = 3;
+    part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
+    
+    relocs = part->reloc_arr;
+    
+    for (i = 0; i < 3; i++) {
+    
+        relocs[i].symbol = &of->symbol_arr[i];
+        relocs[i].howto = &reloc_howtos[RELOC_TYPE_32_NO_BASE];
+    
+    }
+    
+    relocs[0].offset = offsetof (struct pe_import_directory_table, ImportNameTableRVA);
+    relocs[1].offset = offsetof (struct pe_import_directory_table, ImportAddressTableRVA);
+    relocs[2].offset = offsetof (struct pe_import_directory_table, NameRVA);
+    
+    subsection = subsection_find_or_make (section, "4");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content_size = 0;
+    
+    of->symbol_arr[0].name = xstrdup (".idata$4");
+    of->symbol_arr[0].value = 0;
+    of->symbol_arr[0].part = part;
+    of->symbol_arr[0].section_number = 2;
+    
+    subsection = subsection_find_or_make (section, "5");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content_size = 0;
+    
+    of->symbol_arr[1].name = xstrdup (".idata$5");
+    of->symbol_arr[1].value = 0;
+    of->symbol_arr[1].part = part;
+    of->symbol_arr[1].section_number = 3;
+    
+    subsection = subsection_find_or_make (section, "7");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content = xmalloc (part->content_size = ALIGN (strlen (dll_name) + 1, 2));
+    strcpy ((char *) part->content, dll_name);
+    
+    of->symbol_arr[2].name = xstrdup (".idata$7");
+    of->symbol_arr[2].value = 0;
+    of->symbol_arr[2].part = part;
+    of->symbol_arr[2].section_number = 4;
+
+}
+
+static void import_generate_end (void) {
+
+    struct object_file *of;
+    struct subsection *subsection;
+    
+    struct section *section;
+    struct section_part *part;
+    
+    of = object_file_make (FAKE_LD_FILENAME, 3);
+    
+    section = section_find_or_make (".idata");
+    subsection = subsection_find_or_make (section, "4");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content = xmalloc (part->content_size = 4);
+    subsection = subsection_find_or_make (section, "5");
+    
+    part = section_part_new (section, of);
+    subsection_append_section_part (subsection, part);
+    
+    part->content = xmalloc (part->content_size = 4);
+
+}
+
+void pe_archive_end (void) {
+
+    if (current_import_dll_name) {
+    
+        import_generate_end ();
+        free (current_import_dll_name);
+        
+        current_import_dll_name = 0;
+    
+    }
+
+}
+
+void read_pe_import_library (const char *filename, unsigned char *data) {
+
+    struct import_library_header *import_header = (struct import_library_header *) data;
+    
+    const char *import_name;
+    const char *dll_name;
+    
+    if (state->format != LD_FORMAT_I386_PE) {
+        return;
+    }
+    
+    if ((array_to_integer (import_header->Type, 2) & 0x03) == IMPORT_CONST) {
+    
+        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++ not yet supported import header import Type: 0x%x", array_to_integer (import_header->Type, 2) & 0x3);
+        return;
+    
+    }
+    
+    import_name = (const char *) data + sizeof (*import_header);
+    dll_name = import_name + strlen (import_name) + 1;
+    
+    if (current_import_dll_name && strcmp (dll_name, current_import_dll_name)) {
+    
+        import_generate_end ();
+        free (current_import_dll_name);
+        
+        current_import_dll_name = 0;
+    
+    }
+    
+    if (!current_import_dll_name) {
+    
+        current_import_dll_name = xstrdup (dll_name);
+        import_generate_head (filename, current_import_dll_name);
+    
+    }
+    
+    import_generate_import (import_name, array_to_integer (import_header->OrdinalHint, 2), array_to_integer (import_header->Type, 2) & 0x03, array_to_integer (import_header->Type, 2) >> 2, filename);
+
+}
diff --git a/pe.h b/pe.h
index 758acdb6b748ba19f89230e525d6ebba7894d0b5..833e867fd6ab003c14ea6a042f2f0ffb9da1ef5e 100644 (file)
--- a/pe.h
+++ b/pe.h
@@ -203,4 +203,7 @@ void pe_print_help (void);
 void pe_write (const char *filename);
 void pe_use_option (const char *cmd_arg, int idx, const char *optarg);
 
+void pe_archive_end (void);
+void read_pe_import_library (const char *filename, unsigned char *data);
+
 #endif      /* _PE_H */