Added pe-amd64 in --oformat master
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 15 Jun 2026 08:46:16 +0000 (09:46 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 15 Jun 2026 08:46:16 +0000 (09:46 +0100)
coff.c
coff.h
ld.c
ld.h
lib.c
link.c
pe.c
pe.h

diff --git a/coff.c b/coff.c
index 5ce9ae330499b6d37c8958b06f562aea6709faf7..e54e356087d572a1572ce6a729148cb3e9e9f317 100644 (file)
--- a/coff.c
+++ b/coff.c
@@ -42,7 +42,7 @@ struct symbol_table_entry {
 
 };
 
-static void translate_relocation (struct reloc_entry *reloc, struct coff_relocation_entry *input, struct section_part *part) {
+static void translate_relocation32 (struct reloc_entry *reloc, struct coff_relocation_entry *input, struct section_part *part) {
 
     uint16_t type;
     
@@ -97,6 +97,78 @@ static void translate_relocation (struct reloc_entry *reloc, struct coff_relocat
 
 }
 
+static void translate_relocation64 (struct reloc_entry *reloc, struct coff_relocation_entry *input, struct section_part *part) {
+
+    uint16_t type;
+    
+    reloc->symbol = part->of->symbol_arr + array_to_integer (input->SymbolTableIndex, 4, 0);
+    reloc->offset = array_to_integer (input->VirtualAddress, 4, 0);
+    
+    type = array_to_integer (input->Type, 2, 0);
+    
+    switch (type) {
+    
+        case IMAGE_REL_AMD64_ABSOLUTE:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_IGNORED];
+            break;
+        
+        case IMAGE_REL_AMD64_ADDR64:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_64];
+            break;
+        
+        case IMAGE_REL_AMD64_ADDR32:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_32];
+            break;
+        
+        case IMAGE_REL_AMD64_ADDR32NB:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_32_NO_BASE];
+            break;
+        
+        case IMAGE_REL_AMD64_REL32:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+            break;
+        
+        case IMAGE_REL_AMD64_REL32_1:       case IMAGE_REL_AMD64_REL32_2:       case IMAGE_REL_AMD64_REL32_3:
+        case IMAGE_REL_AMD64_REL32_4:       case IMAGE_REL_AMD64_REL32_5:
+        
+            reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+            
+            {
+            
+                unsigned long field = array_to_integer (part->content + reloc->offset, 4, 0);
+                field -= array_to_integer (input->Type, 2, 0) - IMAGE_REL_AMD64_REL32;
+                
+                integer_to_array (field, part->content + reloc->offset, 4, 0);
+            
+            }
+            
+            break;
+        
+        case IMAGE_REL_AMD64_SECTION:   case IMAGE_REL_AMD64_SECREL:    case IMAGE_REL_AMD64_SECREL7:   case IMAGE_REL_AMD64_TOKEN:
+        case IMAGE_REL_AMD64_SREL32:    case IMAGE_REL_AMD64_PAIR:      case IMAGE_REL_AMD64_SSPAN32:
+        
+            report_at (program_name, 0, REPORT_INTERNAL_ERROR, "+++relocation type 0x%04hx not supported yet", array_to_integer (input->Type, 2, 0));
+            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, 0), part->of->filename);
+            exit (EXIT_FAILURE);
+    
+    }
+    
+    if (reloc->symbol->section_number == IMAGE_SYM_CLASS_STATIC) {
+        reloc->n_type = reloc->symbol->section_number;
+    }
+
+}
+
 static unsigned long translate_Characteristics_to_alignment (unsigned long Characteristics) {
 
     unsigned long alignment = 1;
@@ -281,7 +353,7 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
             *p++ = '\0';
         }
         
-        if (state->format == LD_FORMAT_I386_PE && strcmp (section_name, ".drectve") == 0) {
+        if ((state->format == LD_FORMAT_I386_PE || state->format == LD_FORMAT_AMD64_PE) && strcmp (section_name, ".drectve") == 0) {
         
             pe_interpret_dot_drectve_section (/*filename, data, data_size, */data + array_to_integer (section_hdr->PointerToRawData, 4, 0), array_to_integer (section_hdr->SizeOfRawData, 4, 0));
             
@@ -357,7 +429,12 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long
             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 (data[0] == 0x64 && data[1] == 0x86) {
+                    translate_relocation64 (part->reloc_arr + j, reloc_info, part);
+                } else {
+                    translate_relocation32 (part->reloc_arr + j, reloc_info, part);
+                }
             
             }
         
diff --git a/coff.h b/coff.h
index 8aa5fc009e975c3876eab5bf94c28342881a0cfc..bf71a233be862ee0f3d595f1ca4f65a3f1d12bd9 100644 (file)
--- a/coff.h
+++ b/coff.h
@@ -99,6 +99,24 @@ struct coff_relocation_entry {
 
 };
 
+#define     IMAGE_REL_AMD64_ABSOLUTE                        0x0000
+#define     IMAGE_REL_AMD64_ADDR64                          0x0001
+#define     IMAGE_REL_AMD64_ADDR32                          0x0002
+#define     IMAGE_REL_AMD64_ADDR32NB                        0x0003
+#define     IMAGE_REL_AMD64_REL32                           0x0004
+#define     IMAGE_REL_AMD64_REL32_1                         0x0005
+#define     IMAGE_REL_AMD64_REL32_2                         0x0006
+#define     IMAGE_REL_AMD64_REL32_3                         0x0007
+#define     IMAGE_REL_AMD64_REL32_4                         0x0008
+#define     IMAGE_REL_AMD64_REL32_5                         0x0009
+#define     IMAGE_REL_AMD64_SECTION                         0x000A
+#define     IMAGE_REL_AMD64_SECREL                          0x000B
+#define     IMAGE_REL_AMD64_SECREL7                         0x000C
+#define     IMAGE_REL_AMD64_TOKEN                           0x000D
+#define     IMAGE_REL_AMD64_SREL32                          0x000E
+#define     IMAGE_REL_AMD64_PAIR                            0x000F
+#define     IMAGE_REL_AMD64_SSPAN32                         0x0010
+
 #define     IMAGE_REL_I386_ABSOLUTE                         0x0000
 #define     IMAGE_REL_I386_DIR16                            0x0001
 #define     IMAGE_REL_I386_REL16                            0x0002
diff --git a/ld.c b/ld.c
index 796e72166fc2401cc2ebfedfb455f22c4f0ac1f3..f5c8447b677c710d3d4c8e0ee1ddb38f02b3f49a 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -89,7 +89,7 @@ static int read_object_file (const char *filename, unsigned char *data, unsigned
     
     }
     
-    if (data[0] == 0x4C && data[1] == 0x01) {
+    if ((data[0] == 0x4C && data[1] == 0x01) || (data[0] == 0x64 && data[1] == 0x86)) {
     
         read_coff_object (filename, data, data_size);
         return 0;
@@ -390,7 +390,7 @@ static void read_archive (const char *filename, unsigned char *data) {
     
     }
     
-    if (state->format == LD_FORMAT_I386_PE) {
+    if (state->format == LD_FORMAT_AMD64_PE || state->format == LD_FORMAT_I386_PE) {
     
         for (i = 0; i < num_symbols && (!start_header_object_offset || !end_header_object_offset); i++) {
         
@@ -437,7 +437,7 @@ static void read_archive (const char *filename, unsigned char *data) {
     
     }
     
-    if (state->format == LD_FORMAT_I386_PE) {
+    if (state->format == LD_FORMAT_AMD64_PE || state->format == LD_FORMAT_I386_PE) {
     
         if (end_header_object_offset) {
             read_archive_memeber (data + end_header_object_offset, filename);
@@ -529,7 +529,7 @@ int main (int argc, char **argv) {
     
         if (state->format == LD_FORMAT_COM) {
             state->base_address = 0x00000100;
-        } else if (state->format == LD_FORMAT_I386_PE) {
+        } else if (state->format == LD_FORMAT_AMD64_PE || state->format == LD_FORMAT_I386_PE) {
         
             if (state->create_shared_library) {
                 state->base_address = 0x10000000;
@@ -562,7 +562,7 @@ int main (int argc, char **argv) {
         dx_before_link ();
     } else if (state->format == LD_FORMAT_I386_ELKS) {
         elks_before_link ();
-    } else if (state->format == LD_FORMAT_I386_PE) {
+    } else if (state->format == LD_FORMAT_AMD64_PE || state->format == LD_FORMAT_I386_PE) {
         pe_before_link ();
     } else if (state->format == LD_FORMAT_AARCH64_MACHO || state->format == LD_FORMAT_AMD64_MACHO) {
         macho_before_link ();
@@ -629,10 +629,15 @@ int main (int argc, char **argv) {
         elks_write (state->output_filename);
     } else if (state->format == LD_FORMAT_I386_ELF) {
         elf32_write (state->output_filename);
-    } else if (state->format == LD_FORMAT_I386_PE) {
+    } else if (state->format == LD_FORMAT_AMD64_PE || state->format == LD_FORMAT_I386_PE) {
     
         pe_after_link ();
-        pe_write (state->output_filename);
+        
+        if (state->format == LD_FORMAT_AMD64_PE) {
+            pe64_write (state->output_filename);
+        } else {
+            pe32_write (state->output_filename);
+        }
     
     } else if (state->format == LD_FORMAT_I386_COFF) {
     
diff --git a/ld.h b/ld.h
index 5cc67d1b07da08ae850431de459fb7af32103ec9..14b5ad46722a339c50fa190a4bb4118a7495c9fb 100644 (file)
--- a/ld.h
+++ b/ld.h
@@ -63,9 +63,10 @@ struct ld_state {
 
 #define     LD_FORMAT_AMD64_MACHO       (LD_TARGET_MACHINE_AMD64    | 0x11)
 #define     LD_FORMAT_AMD64_ELF         (LD_TARGET_MACHINE_AMD64    | 0x12)
+#define     LD_FORMAT_AMD64_PE          (LD_TARGET_MACHINE_AMD64    | 0x13)
 
-#define     LD_FORMAT_AARCH64_MACHO     (LD_TARGET_MACHINE_AARCH64  | 0x13)
-#define     LD_FORMAT_AARCH64_ELF       (LD_TARGET_MACHINE_AARCH64  | 0x14)
+#define     LD_FORMAT_AARCH64_MACHO     (LD_TARGET_MACHINE_AARCH64  | 0x14)
+#define     LD_FORMAT_AARCH64_ELF       (LD_TARGET_MACHINE_AARCH64  | 0x15)
 
 
 extern struct ld_state *state;
diff --git a/lib.c b/lib.c
index aabed802be44e207211164c4c2dc2be30c426c27..5a0f890e83cf1a5f057a22530c179eaf7f561b72 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -119,7 +119,8 @@ static void print_usage (void) {
         fprintf (stderr, "                                              elf-amd64, elf-i386\n");
         fprintf (stderr, "                                              elks-ia16, elks-i386\n");
         fprintf (stderr, "                                              macho-aarch64, macho-amd64\n");
-        fprintf (stderr, "                                              pe-i386, binary, msdos\n");
+        fprintf (stderr, "                                              pe-i386, pe-amd64\n");
+        fprintf (stderr, "                                              binary, msdos\n");
         fprintf (stderr, "    --image-base <address>            Set base address of the executable.\n");
         
         fprintf (stderr, "\n");
@@ -330,6 +331,30 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) {
             
             }
             
+            if (xstrcasecmp (optarg, "pe-amd64") == 0) {
+            
+                state->format = LD_FORMAT_AMD64_PE;
+                
+                if (state->emulation == LD_EMULATION_NONE) {
+                    state->emulation = LD_EMULATION_I386_PE;
+                }
+                
+                break;
+            
+            }
+            
+            if (xstrcasecmp (optarg, "elf-amd64") == 0) {
+            
+                state->format = LD_FORMAT_AMD64_PE;
+                
+                /*if (state->emulation == LD_EMULATION_NONE) {
+                    state->emulation = LD_EMULATION_I386_COFF;
+                }*/
+                
+                break;
+            
+            }
+            
             if (xstrcasecmp (optarg, "coff-i386") == 0) {
             
                 state->format = LD_FORMAT_I386_COFF;
diff --git a/link.c b/link.c
index 4f76c11481946749cf990928e31546e24810ab7e..31eab401d7801ff571b929dcc27d73395156d45a 100644 (file)
--- a/link.c
+++ b/link.c
@@ -322,7 +322,7 @@ static int has_dgroup = 0;
 
 static unsigned long align_section_if_needed (unsigned long value) {
 
-    if (state->format == LD_FORMAT_I386_PE) {
+    if (state->format == LD_FORMAT_I386_PE || state->format == LD_FORMAT_AMD64_PE) {
         return pe_align_to_file_alignment (value);
     }
     
@@ -539,7 +539,7 @@ static void calculate_section_sizes_and_rvas (void) {
     
     uint64_t rva = 0;
     
-    if (state->format == LD_FORMAT_I386_PE) {
+    if (state->format == LD_FORMAT_AMD64_PE || state->format == LD_FORMAT_I386_PE) {
         rva = pe_get_first_section_rva ();
     } else if (state->format == LD_FORMAT_AMD64_MACHO || state->format == LD_FORMAT_AARCH64_MACHO) {
         rva = macho_get_first_section_rva ();
@@ -970,7 +970,7 @@ static void calculate_entry_point (void) {
             
             }
         
-        } else if (state->format == LD_FORMAT_I386_PE) {
+        } else if (state->format == LD_FORMAT_I386_PE || state->format == LD_FORMAT_AMD64_PE) {
         
             state->entry_symbol_name = xstrdup ("_mainCRTStartup");
             
diff --git a/pe.c b/pe.c
index 7e2f0a48784014c2500f04aed3adf9c410d7c45f..479711785305f4e2ed353744b26f05a3388fe172 100644 (file)
--- a/pe.c
+++ b/pe.c
@@ -24,8 +24,8 @@ static int kill_at = 0, leading_underscore = 1;
 
 static unsigned short subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
 
-static unsigned long section_alignment = DEFAULT_SECTION_ALIGNMENT;
-static unsigned long file_alignment = DEFAULT_FILE_ALIGNMENT;
+static uint64_t section_alignment = DEFAULT_SECTION_ALIGNMENT;
+static uint64_t file_alignment = DEFAULT_FILE_ALIGNMENT;
 
 static const char **def_list = 0;
 long nb_def_list = 0;
@@ -327,7 +327,7 @@ static void export_symbol_callback (struct symbol *symbol) {
     }
     
     name_list->info = (symbol->part->section->flags & SECTION_FLAG_CODE) ? 0 : 1;
-    name_list->next = NULL;
+    name_list->next = 0;
     
     *last_export_name_list_p = name_list;
     last_export_name_list_p = &name_list->next;
@@ -684,7 +684,7 @@ _finish:
 
 static struct section *last_section = 0;
 
-static unsigned long base_of_code = 0;
+static uint64_t base_of_code = 0;
 static unsigned long base_of_data = 0;
 
 static unsigned long size_of_code = 0;
@@ -948,10 +948,9 @@ struct symbol_info *create_symbol_list (struct export_name *export_name, unsigne
     
     free (name);
     
-    for (i = 0; i < num_names; i++, j++) {
+    for (i = 0, j = 0; i < num_names; i++, j++) {
     
         symbol_info = xmalloc (sizeof (*symbol_info));
-        
         symbol_info->name = xmalloc (7 + strlen (export_name[i].name) + 1);
         
         if (leading_underscore) {
@@ -1128,7 +1127,7 @@ static void write_implib (struct export_name *export_names, unsigned long num_na
     info_list = create_symbol_list (export_names, num_names);
     
     offset_count = 2 + 3 + num_names;
-    offsets = xmalloc (offset_count * 4);
+    offsets = xmalloc (offset_count * 8);
     
     module_name = xstrdup (state->output_filename);
     
@@ -1557,8 +1556,14 @@ static void write_implib (struct export_name *export_names, unsigned long num_na
         
         memset (&import_hdr, 0, sizeof (import_hdr));
         
+        integer_to_array (IMAGE_FILE_MACHINE_UNKNOWN, import_hdr.Magic1, 2, 0);
         integer_to_array (0xFFFF, import_hdr.Magic2, 2, 0);
-        integer_to_array (IMAGE_FILE_MACHINE_I386, import_hdr.Machine, 2, 0);
+        
+        if (state->format == LD_FORMAT_AMD64_PE) {
+            integer_to_array (IMAGE_FILE_MACHINE_AMD64, import_hdr.Machine, 2, 0);
+        } else {
+            integer_to_array (IMAGE_FILE_MACHINE_I386, import_hdr.Machine, 2, 0);
+        }
         
         if (leading_underscore) {
             integer_to_array (1 + strlen (export_names[i].name) + 1 + module_name_length + 1, import_hdr.SizeOfData, 4, 0);
@@ -1930,7 +1935,13 @@ void pe_before_link (void) {
     
     }
     
-    state->size_of_headers = sizeof (struct msdos_header) + sizeof (dos_stub) + sizeof (struct pe_header) + sizeof (struct pe_optional_header);
+    state->size_of_headers = sizeof (struct msdos_header) + sizeof (dos_stub) + sizeof (struct pe_header);
+    
+    if (state->format == LD_FORMAT_AMD64_PE) {
+        state->size_of_headers += sizeof (struct pe_optional_header_plus);
+    } else {
+        state->size_of_headers += sizeof (struct pe_optional_header);
+    }
     
     state->size_of_headers += NUMBER_OF_DATA_DIRECTORIES * sizeof (struct pe_image_data_directory);
     state->size_of_headers += sizeof (struct pe_section_table_entry) * section_count ();
@@ -1966,7 +1977,7 @@ void pe_before_link (void) {
 
 }
 
-void pe_write (const char *filename) {
+void pe32_write (const char *filename) {
 
     FILE *fp;
     
@@ -2090,9 +2101,9 @@ void pe_write (const char *filename) {
     
         unsigned short characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
         
-        if (can_be_relocated) {
+        /*if (can_be_relocated) {
             characteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
-        }
+        }*/
         
         write721_to_byte_array (opthdr->DllCharacteristics, characteristics);
     
@@ -2221,6 +2232,263 @@ void pe_write (const char *filename) {
 
 }
 
+void pe64_write (const char *filename) {
+
+    FILE *fp;
+    
+    unsigned long data_size = 0, checksum_pos = 0;
+    unsigned char *data, *pos;
+    
+    struct msdos_header *doshdr;
+    struct pe_header *pehdr;
+    struct pe_optional_header_plus *opthdr;
+    
+    struct section *section;
+    unsigned long size_of_optional_header;
+    
+    if (!(fp = fopen (filename, "wb"))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename);
+        return;
+    
+    }
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        if (!section->is_bss) {
+            data_size += ALIGN (section->total_size, file_alignment);
+        }
+    
+    }
+    
+    data_size += state->size_of_headers;
+    
+    data = xmalloc (data_size);
+    write_sections (data);
+    
+    doshdr = (struct msdos_header *) data;
+    
+    pehdr = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub));
+    opthdr = (struct pe_optional_header_plus *) ((char *) pehdr + sizeof (*pehdr));
+    
+    pos = (unsigned char *) opthdr + sizeof (*opthdr);
+    
+    doshdr->e_magic[0] = 'M';
+    doshdr->e_magic[1] = 'Z';
+    
+    write721_to_byte_array (doshdr->e_cblp, 0x0090);
+    write721_to_byte_array (doshdr->e_cp, 0x0003);
+    
+    write721_to_byte_array (doshdr->e_cparhdr, ALIGN (sizeof (*doshdr), 16) / 16);
+    
+    write721_to_byte_array (doshdr->e_maxalloc, 0xFFFF);
+    write721_to_byte_array (doshdr->e_sp, 0x00B8);
+    
+    write721_to_byte_array (doshdr->e_lfarlc, sizeof (*doshdr));
+    write741_to_byte_array (doshdr->e_lfanew, sizeof (*doshdr) + sizeof (dos_stub));
+    
+    memcpy ((char *) data + array_to_integer (doshdr->e_lfarlc, 2, 0), dos_stub, sizeof (dos_stub));
+    
+    
+    pehdr->Signature[0] = 'P';
+    pehdr->Signature[1] = 'E';
+    
+    write721_to_byte_array (pehdr->Machine, IMAGE_FILE_MACHINE_AMD64);
+    write721_to_byte_array (pehdr->NumberOfSections, section_count ());
+    write741_to_byte_array (pehdr->TimeDateStamp, time (0));
+    
+    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);
+    
+    {
+    
+        unsigned short characteristics = 0;
+        
+        characteristics |= IMAGE_FILE_EXECUTABLE_IMAGE;
+        /*characteristics |= IMAGE_FILE_LINE_NUMS_STRIPPED;*/
+        /*characteristics |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;*/
+        characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+        characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
+        
+        if (state->create_shared_library) {
+            characteristics |= IMAGE_FILE_DLL;
+        }
+        
+        if (!can_be_relocated) {
+            characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+        }
+        
+        write721_to_byte_array (pehdr->Characteristics, characteristics);
+    
+    }
+    
+    
+    write721_to_byte_array (opthdr->Magic, IMAGE_FILE_MAGIC_AMD64);
+    
+    opthdr->MajorLinkerVersion = 0;
+    opthdr->MinorLinkerVersion = 10;
+    
+    write741_to_byte_array (opthdr->SizeOfCode, ALIGN (size_of_code, file_alignment));
+    write741_to_byte_array (opthdr->SizeOfInitializedData, ALIGN (size_of_initialized_data, file_alignment));
+    write741_to_byte_array (opthdr->SizeOfUninitializedData, ALIGN (size_of_uninitialized_data, file_alignment));
+    
+    write741_to_byte_array (opthdr->AddressOfEntryPoint, state->entry_point);
+    
+    write741_to_byte_array (opthdr->BaseOfCode, base_of_code);
+    integer_to_array (state->base_address, opthdr->ImageBase, 8, 0);
+    
+    write741_to_byte_array (opthdr->SectionAlignment, section_alignment);
+    write741_to_byte_array (opthdr->FileAlignment, file_alignment);
+    
+    write721_to_byte_array (opthdr->MajorOperatingSystemVersion, 4);
+    write721_to_byte_array (opthdr->MajorImageVersion, 1);
+    write721_to_byte_array (opthdr->MajorSubsystemVersion, 4);
+    
+    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, 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;
+        
+        if (!(bss_section = section_find (".bss"))) {
+        
+            integer_to_array (section_alignment << 9, opthdr->SizeOfStackReserved, 8, 0);
+            integer_to_array (0x1000, opthdr->SizeOfStackCommit, 8, 0);
+            integer_to_array (section_alignment << 8, opthdr->SizeOfHeapReserved, 8, 0);
+            integer_to_array (0x1000, opthdr->SizeOfHeapCommit, 8, 0);
+        
+        } else {
+        
+            uint64_t ibss_addr = bss_section->rva;
+            uint64_t ibss_size = bss_section->total_size;
+            
+            uint64_t stack_addr = ibss_addr + ibss_size;
+            uint64_t stack_size = ALIGN (stack_addr, section_alignment);
+            
+            integer_to_array (section_alignment << 9, opthdr->SizeOfStackReserved, 8, 0);
+            integer_to_array (ALIGN (stack_addr % 16 + stack_size, section_alignment), opthdr->SizeOfStackCommit, 8, 0);
+            integer_to_array (section_alignment << 8, opthdr->SizeOfHeapReserved, 8, 0);
+            integer_to_array (ALIGN (stack_addr % 16 + stack_size, section_alignment), opthdr->SizeOfHeapCommit, 8, 0);
+        
+        }
+    
+    }
+    
+    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")) && iat_first_part) {
+                    
+                        write741_to_byte_array (idd->VirtualAddress, iat_first_part->rva);
+                        write741_to_byte_array (idd->Size, iat_last_part->rva + iat_last_part->content_size - iat_first_part->rva);
+                    
+                    }
+                    
+                    break;
+            
+            }
+            
+            pos += sizeof (*idd);
+        
+        }
+    
+    }
+    
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        struct pe_section_table_entry *hdr = section->object_dependent_data;
+        
+        memcpy (pos, hdr, sizeof (*hdr));
+        pos += sizeof (*hdr);
+        
+        free (hdr);
+    
+    }
+    
+    
+    checksum_pos = sizeof (*doshdr) + sizeof (dos_stub) + sizeof (*pehdr) + offsetof (struct pe_optional_header, Checksum);
+    write741_to_byte_array (opthdr->Checksum, calculate_checksum (data, checksum_pos, data_size));
+    
+    if (fwrite (data, data_size, 1, fp) != 1) {
+        report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", filename);
+    }
+    
+    free (data);
+    fclose (fp);
+
+}
+
 void pe_print_help (void) {
 
     fprintf (stderr, "i386pe:\n\n");
@@ -2288,7 +2556,7 @@ static void import_generate_import (const char *import_name, short ordinal_hint,
     part = section_part_new (section, of);
     subsection_append_section_part (subsection, part);
     
-    part->content = xmalloc (part->content_size = 4);
+    part->content = xmalloc (part->content_size = (state->format == LD_FORMAT_AMD64_PE ? 8 : 4));
     part->reloc_cnt = 1;
     part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
     
@@ -2303,7 +2571,7 @@ static void import_generate_import (const char *import_name, short ordinal_hint,
     part = section_part_new (section, of);
     subsection_append_section_part (subsection, part);
     
-    part->content = xmalloc (part->content_size = 4);
+    part->content = xmalloc (part->content_size = (state->format == LD_FORMAT_AMD64_PE ? 8 : 4));
     
     symbol->name = xstrdup (".idata$5");
     symbol->value = 0;
@@ -2394,8 +2662,13 @@ static void import_generate_import (const char *import_name, short ordinal_hint,
         relocs = part->reloc_arr;
         
         relocs[0].symbol = &of->symbol_arr[0];
-        relocs[0].howto = &reloc_howtos[RELOC_TYPE_32];
         relocs[0].offset = 2;
+        
+        if (state->format == LD_FORMAT_AMD64_PE) {
+            relocs[0].howto = &reloc_howtos[RELOC_TYPE_PC32];
+        } else {
+            relocs[0].howto = &reloc_howtos[RELOC_TYPE_32];
+        }
     
     }
     
@@ -2526,13 +2799,13 @@ static void import_generate_end (void) {
     part = section_part_new (section, of);
     subsection_append_section_part (subsection, part);
     
-    part->content = xmalloc (part->content_size = 4);
+    part->content = xmalloc (part->content_size = (state->format == LD_FORMAT_AMD64_PE ? 8 : 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);
+    part->content = xmalloc (part->content_size = (state->format == LD_FORMAT_AMD64_PE ? 8 : 4));
 
 }
 
@@ -2556,7 +2829,7 @@ void read_pe_import_library (const char *filename, unsigned char *data) {
     const char *import_name;
     const char *dll_name;
     
-    if (state->format != LD_FORMAT_I386_PE) {
+    if (state->format != LD_FORMAT_I386_PE && state->format != LD_FORMAT_AMD64_PE) {
         return;
     }
     
diff --git a/pe.h b/pe.h
index e63d8fa5c2fcb642d6f260b6351aa646efdceea7..ad7dd1b32e8aa64427c84ac3cc64d0ec047179db 100644 (file)
--- a/pe.h
+++ b/pe.h
@@ -60,14 +60,18 @@ struct pe_header {
 
 };
 
+#define     IMAGE_FILE_MACHINE_UNKNOWN                      0x0000
+#define     IMAGE_FILE_MACHINE_AMD64                        0x8664
 #define     IMAGE_FILE_MACHINE_I386                         0x014C
 
 #define     IMAGE_FILE_RELOCS_STRIPPED                      0x0001
 #define     IMAGE_FILE_EXECUTABLE_IMAGE                     0x0002
 #define     IMAGE_FILE_LINE_NUMS_STRIPPED                   0x0004
 #define     IMAGE_FILE_LOCAL_SYMS_STRIPPED                  0x0008
+#define     IMAGE_FILE_LARGE_ADDRESS_AWARE                  0x0020
 #define     IMAGE_FILE_32BIT_MACHINE                        0x0100
 #define     IMAGE_FILE_DEBUG_STRIPPED                       0x0200
+#define     IMAGE_FILE_DLL                                  0x2000
 
 struct pe_optional_header {
 
@@ -115,7 +119,48 @@ struct pe_optional_header {
 
 };
 
+struct pe_optional_header_plus {
+
+    unsigned char Magic[2];
+    
+    unsigned char MajorLinkerVersion;
+    unsigned char MinorLinkerVersion;
+    
+    unsigned char SizeOfCode[4];
+    unsigned char SizeOfInitializedData[4];
+    unsigned char SizeOfUninitializedData[4];
+    unsigned char AddressOfEntryPoint[4];
+    
+    unsigned char BaseOfCode[4];
+    unsigned char ImageBase[8];
+    
+    unsigned char SectionAlignment[4];
+    unsigned char FileAlignment[4];
+    unsigned char MajorOperatingSystemVersion[2];
+    unsigned char MinorOperatingSystemVersion[2];
+    unsigned char MajorImageVersion[2];
+    unsigned char MinorImageVersion[2];
+    unsigned char MajorSubsystemVersion[2];
+    unsigned char MinorSubsystemVersion[2];
+    unsigned char Win32VersionValue[4];
+    unsigned char SizeOfImage[4];
+    unsigned char SizeOfHeaders[4];
+    unsigned char Checksum[4];
+    unsigned char Subsystem[2];
+    unsigned char DllCharacteristics[2];
+    
+    unsigned char SizeOfStackReserved[8];
+    unsigned char SizeOfStackCommit[8];
+    unsigned char SizeOfHeapReserved[8];
+    unsigned char SizeOfHeapCommit[8];
+    
+    unsigned char LoaderFlags[4];
+    unsigned char NumberOfRvaAndSizes[4];
+
+};
+
 #define     IMAGE_FILE_MAGIC_I386                           0x010B
+#define     IMAGE_FILE_MAGIC_AMD64                          0x020B
 
 struct pe_section_table_entry {
 
@@ -236,10 +281,12 @@ void pe_after_link (void);
 void pe_before_link (void);
 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 pe32_write (const char *filename);
+void pe64_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 */