- Fix various warnings in inflib (thanks to Ged for help with what appears to be...
[reactos.git] / reactos / tools / pefixup.c
index 9f6e9a0..8c0ca7a 100644 (file)
-/*\r
- * PE Fixup Utility\r
- * Copyright (C) 2005 Filip Navara\r
- *\r
- * The purpose of this utility is fix PE binaries generated by binutils and\r
- * to manipulate flags that can't be set by binutils.\r
- *\r
- * Currently two features are implemented:\r
- *\r
- * - Setting flags on PE sections for use by drivers. The sections\r
- *   .text, .data, .idata, .bss are marked as non-pageable and\r
- *   non-discarable, section PAGE is marked as pageable and section\r
- *   INIT is marked as discaradable.\r
- *\r
- * - Sorting of export name table in executables. DLLTOOL has bug\r
- *   in sorting algorithm when the --kill-at flag is used. The exports\r
- *   are sorted in the decorated form and so the fastcall symbols are\r
- *   incorrectly put at the beginning of export table. This option\r
- *   allow to correct sort the table, so binary search can be used\r
- *   to process them.\r
- */\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <fcntl.h>\r
-\r
-/* The following definitions are ripped from MinGW W32API headers. We don't\r
-   use these headers directly in order to allow compilation on Linux hosts. */\r
-\r
-typedef unsigned char BYTE;\r
-typedef unsigned short WORD;\r
-typedef unsigned int DWORD;\r
-typedef int LONG;\r
-\r
-#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16\r
-#define IMAGE_SIZEOF_SHORT_NAME 8\r
-#define IMAGE_DOS_SIGNATURE 0x5A4D\r
-#define IMAGE_NT_SIGNATURE 0x00004550\r
-#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000\r
-#define IMAGE_SCN_MEM_NOT_PAGED 0x8000000\r
-#define FIELD_OFFSET(t,f) ((LONG)&(((t*)0)->f))\r
-#define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((DWORD)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader))\r
-#define IMAGE_DIRECTORY_ENTRY_EXPORT 0\r
-\r
-#pragma pack(push,2)\r
-typedef struct _IMAGE_DOS_HEADER {\r
-       WORD e_magic;\r
-       WORD e_cblp;\r
-       WORD e_cp;\r
-       WORD e_crlc;\r
-       WORD e_cparhdr;\r
-       WORD e_minalloc;\r
-       WORD e_maxalloc;\r
-       WORD e_ss;\r
-       WORD e_sp;\r
-       WORD e_csum;\r
-       WORD e_ip;\r
-       WORD e_cs;\r
-       WORD e_lfarlc;\r
-       WORD e_ovno;\r
-       WORD e_res[4];\r
-       WORD e_oemid;\r
-       WORD e_oeminfo;\r
-       WORD e_res2[10];\r
-       LONG e_lfanew;\r
-} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;\r
-#pragma pack(pop)\r
-#pragma pack(push,4)\r
-typedef struct _IMAGE_EXPORT_DIRECTORY {\r
-       DWORD Characteristics;\r
-       DWORD TimeDateStamp;\r
-       WORD MajorVersion;\r
-       WORD MinorVersion;\r
-       DWORD Name;\r
-       DWORD Base;\r
-       DWORD NumberOfFunctions;\r
-       DWORD NumberOfNames;\r
-       DWORD AddressOfFunctions;\r
-       DWORD AddressOfNames;\r
-       DWORD AddressOfNameOrdinals;\r
-} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;\r
-typedef struct _IMAGE_FILE_HEADER {\r
-       WORD Machine;\r
-       WORD NumberOfSections;\r
-       DWORD TimeDateStamp;\r
-       DWORD PointerToSymbolTable;\r
-       DWORD NumberOfSymbols;\r
-       WORD SizeOfOptionalHeader;\r
-       WORD Characteristics;\r
-} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;\r
-typedef struct _IMAGE_DATA_DIRECTORY {\r
-       DWORD VirtualAddress;\r
-       DWORD Size;\r
-} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;\r
-typedef struct _IMAGE_OPTIONAL_HEADER {\r
-       WORD Magic;\r
-       BYTE MajorLinkerVersion;\r
-       BYTE MinorLinkerVersion;\r
-       DWORD SizeOfCode;\r
-       DWORD SizeOfInitializedData;\r
-       DWORD SizeOfUninitializedData;\r
-       DWORD AddressOfEntryPoint;\r
-       DWORD BaseOfCode;\r
-       DWORD BaseOfData;\r
-       DWORD ImageBase;\r
-       DWORD SectionAlignment;\r
-       DWORD FileAlignment;\r
-       WORD MajorOperatingSystemVersion;\r
-       WORD MinorOperatingSystemVersion;\r
-       WORD MajorImageVersion;\r
-       WORD MinorImageVersion;\r
-       WORD MajorSubsystemVersion;\r
-       WORD MinorSubsystemVersion;\r
-       DWORD Reserved1;\r
-       DWORD SizeOfImage;\r
-       DWORD SizeOfHeaders;\r
-       DWORD CheckSum;\r
-       WORD Subsystem;\r
-       WORD DllCharacteristics;\r
-       DWORD SizeOfStackReserve;\r
-       DWORD SizeOfStackCommit;\r
-       DWORD SizeOfHeapReserve;\r
-       DWORD SizeOfHeapCommit;\r
-       DWORD LoaderFlags;\r
-       DWORD NumberOfRvaAndSizes;\r
-       IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];\r
-} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;\r
-typedef struct _IMAGE_NT_HEADERS {\r
-       DWORD Signature;\r
-       IMAGE_FILE_HEADER FileHeader;\r
-       IMAGE_OPTIONAL_HEADER OptionalHeader;\r
-} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;\r
-typedef struct _IMAGE_SECTION_HEADER {\r
-       BYTE Name[IMAGE_SIZEOF_SHORT_NAME];\r
-       union {\r
-               DWORD PhysicalAddress;\r
-               DWORD VirtualSize;\r
-       } Misc;\r
-       DWORD VirtualAddress;\r
-       DWORD SizeOfRawData;\r
-       DWORD PointerToRawData;\r
-       DWORD PointerToRelocations;\r
-       DWORD PointerToLinenumbers;\r
-       WORD NumberOfRelocations;\r
-       WORD NumberOfLinenumbers;\r
-       DWORD Characteristics;\r
-} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;\r
-#pragma pack(pop)\r
-\r
-/* End of ripped definitions */\r
-\r
-typedef struct _export_t {\r
-   DWORD name;\r
-   WORD ordinal;\r
-} export_t;\r
-\r
-unsigned char *buffer;\r
-PIMAGE_DOS_HEADER dos_header;\r
-PIMAGE_NT_HEADERS nt_header;\r
-\r
-void *rva_to_ptr(DWORD rva)\r
-{\r
-   PIMAGE_SECTION_HEADER section_header;\r
-   unsigned int i;\r
-\r
-   for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);\r
-        i < nt_header->OptionalHeader.NumberOfRvaAndSizes;\r
-        i++, section_header++)\r
-   {\r
-      if (rva >= section_header->VirtualAddress &&\r
-          rva < section_header->VirtualAddress +\r
-                section_header->Misc.VirtualSize)\r
-      {\r
-         return buffer + rva - section_header->VirtualAddress +\r
-                section_header->PointerToRawData;\r
-      }\r
-   }\r
-\r
-   return NULL;\r
-}\r
-\r
-int export_compare_func(const void *a, const void *b)\r
-{\r
-   const export_t *ap = a;\r
-   const export_t *bp = b;\r
-   char *an = rva_to_ptr(ap->name);\r
-   char *bn = rva_to_ptr(bp->name);\r
-   return strcmp(an, bn);\r
-}\r
-\r
-int main(int argc, char **argv)\r
-{\r
-   int fd_in, fd_out;\r
-   long len;\r
-   PIMAGE_SECTION_HEADER section_header;\r
-   PIMAGE_DATA_DIRECTORY data_dir;\r
-   unsigned int i;\r
-   unsigned long checksum;\r
-   int fixup_exports = 0;\r
-   int fixup_sections = 0;\r
-\r
-   /*\r
-    * Process parameters.\r
-    */\r
-\r
-   if (argc < 2)\r
-   {\r
-      printf("Usage: %s <filename> <options>\n"\r
-             "Options:\n"\r
-             " -sections Sets section flags for PE image.\n"\r
-             " -exports Sort the names in export table.\n",\r
-             argv[0]);\r
-      return 1;\r
-   }\r
-\r
-   for (i = 2; i < argc; i++)\r
-   {\r
-      if (!strcmp(argv[i], "-sections"))\r
-         fixup_sections = 1;\r
-      else if (!strcmp(argv[i], "-exports"))\r
-         fixup_exports = 1;\r
-      else\r
-         { printf("Invalid option: %s\n", argv[i]); return 1; }\r
-   }\r
-\r
-   if (fixup_sections == 0 && fixup_exports == 0)\r
-   {\r
-      printf("Nothing to do.\n");\r
-      return 0;\r
-   }\r
-\r
-   /*\r
-    * Read the whole file to memory.\r
-    */\r
-\r
-   fd_in = open(argv[1], O_RDONLY | O_BINARY);\r
-   if (fd_in == 0)\r
-   {\r
-      printf("Can't open input file.\n");\r
-      return 1;\r
-   }\r
-\r
-   len = lseek(fd_in, 0, SEEK_END);\r
-   if (len < sizeof(IMAGE_DOS_HEADER))\r
-   {\r
-      close(fd_in);\r
-      printf("'%s' isn't a PE image.\n", argv[1]);\r
-      return 1;\r
-   }\r
-\r
-   buffer = malloc((len + 1) & ~1);\r
-   if (buffer == NULL)\r
-   {\r
-      close(fd_in);\r
-      printf("Not enough memory available.\n");\r
-      return 1;\r
-   }\r
-\r
-   /* Read the whole input file into a buffer */\r
-   lseek(fd_in, 0, SEEK_SET);\r
-   read(fd_in, buffer, len);\r
-   if (len & 1)\r
-      buffer[len] = 0;\r
-\r
-   close(fd_in);\r
-\r
-   /*\r
-    * Check the headers and save pointers to them.\r
-    */\r
-\r
-   dos_header = (PIMAGE_DOS_HEADER)buffer;\r
-   nt_header = (PIMAGE_NT_HEADERS)(buffer + dos_header->e_lfanew);\r
-   \r
-   if (dos_header->e_magic != IMAGE_DOS_SIGNATURE ||\r
-       nt_header->Signature != IMAGE_NT_SIGNATURE)\r
-   {\r
-      printf("'%s' isn't a PE image.\n", argv[1]);\r
-      free(buffer);\r
-      return 1;\r
-   }\r
-\r
-   if (fixup_exports)\r
-   {\r
-      /* Sort export directory */\r
-      data_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];\r
-      if (data_dir->Size != 0)\r
-      {\r
-         PIMAGE_EXPORT_DIRECTORY export_directory;\r
-         DWORD *name_ptr;\r
-         WORD *ordinal_ptr;\r
-         export_t *exports;\r
-\r
-         export_directory = (PIMAGE_EXPORT_DIRECTORY)rva_to_ptr(data_dir->VirtualAddress);\r
-         if (export_directory != NULL)\r
-         {\r
-            exports = malloc(sizeof(export_t) * export_directory->NumberOfNames);\r
-            if (exports == NULL)\r
-            {\r
-               printf("Not enough memory.\n");\r
-               free(buffer);\r
-               return 1;\r
-            }\r
-\r
-            name_ptr = (DWORD *)rva_to_ptr(export_directory->AddressOfNames);\r
-            ordinal_ptr = (WORD *)rva_to_ptr(export_directory->AddressOfNameOrdinals);\r
-\r
-            for (i = 0; i < export_directory->NumberOfNames; i++)\r
-            {\r
-               exports[i].name = name_ptr[i];\r
-               exports[i].ordinal = ordinal_ptr[i];\r
-            }\r
-\r
-            qsort(exports, export_directory->NumberOfNames, sizeof(export_t),\r
-                  export_compare_func);\r
-\r
-            for (i = 0; i < export_directory->NumberOfNames; i++)\r
-            {\r
-               name_ptr[i] = exports[i].name;\r
-               ordinal_ptr[i] = exports[i].ordinal;\r
-            }\r
-\r
-            free(exports);\r
-         }\r
-      }\r
-   }\r
-\r
-   if (fixup_sections)\r
-   {\r
-      /* Update section flags */\r
-      for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);\r
-           i < nt_header->OptionalHeader.NumberOfRvaAndSizes;\r
-           i++, section_header++)\r
-      {\r
-         if (!strcmp(section_header->Name, ".text") ||\r
-             !strcmp(section_header->Name, ".data") ||\r
-             !strcmp(section_header->Name, ".idata") ||\r
-             !strcmp(section_header->Name, ".bss"))\r
-         {\r
-            section_header->Characteristics |= IMAGE_SCN_MEM_NOT_PAGED;\r
-            section_header->Characteristics &= ~IMAGE_SCN_MEM_DISCARDABLE;\r
-         }\r
-         else if (!strcmp(section_header->Name, "INIT"))\r
-         {\r
-            section_header->Characteristics |= IMAGE_SCN_MEM_DISCARDABLE;\r
-         }\r
-         else if (!strcmp(section_header->Name, "PAGE"))\r
-         {\r
-            section_header->Characteristics |= IMAGE_SCN_MEM_NOT_PAGED;\r
-         }\r
-      }\r
-   }\r
-\r
-   /* Recalculate checksum */\r
-   nt_header->OptionalHeader.CheckSum = 0;\r
-   checksum = 0;\r
-   for (i = 0; i < len; i += 2)\r
-   {\r
-      checksum += *(unsigned short *)(buffer + i);\r
-      checksum = (checksum + (checksum >> 16)) & 0xffff;\r
-   }\r
-   checksum += len;\r
-   nt_header->OptionalHeader.CheckSum = checksum;\r
-\r
-   /* Write the output file */\r
-   fd_out = open(argv[1], O_WRONLY | O_BINARY);\r
-   write(fd_out, buffer, len);\r
-   close(fd_out);\r
-\r
-   return 0;\r
-}\r
+/*
+ * PE Fixup Utility
+ * Copyright (C) 2005 Filip Navara
+ *
+ * The purpose of this utility is fix PE binaries generated by binutils and
+ * to manipulate flags that can't be set by binutils.
+ *
+ * Currently two features are implemented:
+ *
+ * - Setting flags on PE sections for use by drivers. The sections
+ *   .text, .data, .idata, .bss are marked as non-pageable and
+ *   non-discarable, section PAGE is marked as pageable and section
+ *   INIT is marked as discaradable.
+ *
+ * - Sorting of export name table in executables. DLLTOOL has bug
+ *   in sorting algorithm when the --kill-at flag is used. The exports
+ *   are sorted in the decorated form and so the fastcall symbols are
+ *   incorrectly put at the beginning of export table. This option
+ *   allow to correct sort the table, so binary search can be used
+ *   to process them.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* The following definitions are ripped from MinGW W32API headers. We don't
+   use these headers directly in order to allow compilation on Linux hosts. */
+
+typedef unsigned char BYTE, *PBYTE;
+typedef unsigned short WORD;
+typedef unsigned int DWORD;
+typedef int LONG;
+typedef long LONG_PTR;
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+#define IMAGE_SIZEOF_SHORT_NAME 8
+#define IMAGE_DOS_SIGNATURE 0x5A4D
+#define IMAGE_NT_SIGNATURE 0x00004550
+#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x8000000
+#define FIELD_OFFSET(t,f) ((LONG)(LONG_PTR)&(((t*)0)->f))
+#define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((unsigned long)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader))
+#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
+
+#pragma pack(2)
+typedef struct _IMAGE_DOS_HEADER {
+       WORD e_magic;
+       WORD e_cblp;
+       WORD e_cp;
+       WORD e_crlc;
+       WORD e_cparhdr;
+       WORD e_minalloc;
+       WORD e_maxalloc;
+       WORD e_ss;
+       WORD e_sp;
+       WORD e_csum;
+       WORD e_ip;
+       WORD e_cs;
+       WORD e_lfarlc;
+       WORD e_ovno;
+       WORD e_res[4];
+       WORD e_oemid;
+       WORD e_oeminfo;
+       WORD e_res2[10];
+       LONG e_lfanew;
+} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
+#pragma pack(4)
+#pragma pack(4)
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+       DWORD Characteristics;
+       DWORD TimeDateStamp;
+       WORD MajorVersion;
+       WORD MinorVersion;
+       DWORD Name;
+       DWORD Base;
+       DWORD NumberOfFunctions;
+       DWORD NumberOfNames;
+       DWORD AddressOfFunctions;
+       DWORD AddressOfNames;
+       DWORD AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
+typedef struct _IMAGE_FILE_HEADER {
+       WORD Machine;
+       WORD NumberOfSections;
+       DWORD TimeDateStamp;
+       DWORD PointerToSymbolTable;
+       DWORD NumberOfSymbols;
+       WORD SizeOfOptionalHeader;
+       WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+typedef struct _IMAGE_DATA_DIRECTORY {
+       DWORD VirtualAddress;
+       DWORD Size;
+} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
+typedef struct _IMAGE_OPTIONAL_HEADER {
+       WORD Magic;
+       BYTE MajorLinkerVersion;
+       BYTE MinorLinkerVersion;
+       DWORD SizeOfCode;
+       DWORD SizeOfInitializedData;
+       DWORD SizeOfUninitializedData;
+       DWORD AddressOfEntryPoint;
+       DWORD BaseOfCode;
+       DWORD BaseOfData;
+       DWORD ImageBase;
+       DWORD SectionAlignment;
+       DWORD FileAlignment;
+       WORD MajorOperatingSystemVersion;
+       WORD MinorOperatingSystemVersion;
+       WORD MajorImageVersion;
+       WORD MinorImageVersion;
+       WORD MajorSubsystemVersion;
+       WORD MinorSubsystemVersion;
+       DWORD Reserved1;
+       DWORD SizeOfImage;
+       DWORD SizeOfHeaders;
+       DWORD CheckSum;
+       WORD Subsystem;
+       WORD DllCharacteristics;
+       DWORD SizeOfStackReserve;
+       DWORD SizeOfStackCommit;
+       DWORD SizeOfHeapReserve;
+       DWORD SizeOfHeapCommit;
+       DWORD LoaderFlags;
+       DWORD NumberOfRvaAndSizes;
+       IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;
+typedef struct _IMAGE_NT_HEADERS {
+       DWORD Signature;
+       IMAGE_FILE_HEADER FileHeader;
+       IMAGE_OPTIONAL_HEADER OptionalHeader;
+} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
+typedef struct _IMAGE_SECTION_HEADER {
+       BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
+       union {
+               DWORD PhysicalAddress;
+               DWORD VirtualSize;
+       } Misc;
+       DWORD VirtualAddress;
+       DWORD SizeOfRawData;
+       DWORD PointerToRawData;
+       DWORD PointerToRelocations;
+       DWORD PointerToLinenumbers;
+       WORD NumberOfRelocations;
+       WORD NumberOfLinenumbers;
+       DWORD Characteristics;
+} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
+#pragma pack(4)
+
+/* End of ripped definitions */
+
+typedef struct _export_t {
+   DWORD name;
+   WORD ordinal;
+} export_t;
+
+unsigned char *buffer;
+PIMAGE_DOS_HEADER dos_header;
+PIMAGE_NT_HEADERS nt_header;
+
+static inline WORD dtohs(WORD in)
+{
+    PBYTE in_ptr = (PBYTE)&in;
+    return in_ptr[0] | (in_ptr[1] << 8);
+}
+
+static inline WORD htods(WORD in)
+{
+    WORD out;
+    PBYTE out_ptr = (PBYTE)&out;
+    out_ptr[0] = in; out_ptr[1] = in >> 8;
+    return out;
+}
+
+static inline DWORD dtohl(DWORD in)
+{
+    PBYTE in_ptr = (PBYTE)&in;
+    return in_ptr[0] | (in_ptr[1] << 8) | (in_ptr[2] << 16) | (in_ptr[3] << 24);
+}
+
+static inline DWORD htodl(DWORD in)
+{
+    DWORD out;
+    PBYTE out_ptr = (PBYTE)&out;
+    out_ptr[0] = in      ; out_ptr[1] = in >> 8;
+    out_ptr[2] = in >> 16; out_ptr[3] = in >> 24;
+    return out;
+}
+
+void *rva_to_ptr(DWORD rva)
+{
+   PIMAGE_SECTION_HEADER section_header;
+   unsigned int i;
+
+   for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);
+        i < dtohl(nt_header->FileHeader.NumberOfSections);
+        i++, section_header++)
+   {
+      if (rva >= dtohl(section_header->VirtualAddress) &&
+          rva < dtohl(section_header->VirtualAddress) +
+                dtohl(section_header->Misc.VirtualSize))
+      {
+         return buffer + rva - dtohl(section_header->VirtualAddress) +
+                dtohl(section_header->PointerToRawData);
+      }
+   }
+
+   return NULL;
+}
+
+int export_compare_func(const void *a, const void *b)
+{
+   const export_t *ap = a;
+   const export_t *bp = b;
+   char *an = rva_to_ptr(ap->name);
+   char *bn = rva_to_ptr(bp->name);
+   return strcmp(an, bn);
+}
+
+int main(int argc, char **argv)
+{
+   int fd_in, fd_out;
+   long len;
+   char hdrbuf[4] = { }, elfhdr[4] = { '\177', 'E', 'L', 'F' };
+   PIMAGE_SECTION_HEADER section_header;
+   PIMAGE_DATA_DIRECTORY data_dir;
+   unsigned int i;
+   unsigned long checksum;
+   int fixup_exports = 0;
+   int fixup_sections = 0;
+
+   /*
+    * Process parameters.
+    */
+
+   if (argc < 2)
+   {
+      printf("Usage: %s <filename> <options>\n"
+             "Options:\n"
+             " -sections Sets section flags for PE image.\n"
+             " -exports Sort the names in export table.\n",
+             argv[0]);
+      return 1;
+   }
+
+   for (i = 2; i < argc; i++)
+   {
+      if (!strcmp(argv[i], "-sections"))
+         fixup_sections = 1;
+      else if (!strcmp(argv[i], "-exports"))
+         fixup_exports = 1;
+      else
+         { printf("Invalid option: %s\n", argv[i]); return 1; }
+   }
+
+   if (fixup_sections == 0 && fixup_exports == 0)
+   {
+      printf("Nothing to do.\n");
+      return 0;
+   }
+
+   /*
+    * Read the whole file to memory.
+    */
+
+   fd_in = open(argv[1], O_RDONLY | O_BINARY);
+   if (fd_in == 0)
+   {
+      printf("Can't open input file.\n");
+      return 1;
+   }
+
+   /*
+    * PowerPC ReactOS uses elf, so doesn't need pefixup
+    */
+   len = read(fd_in, hdrbuf, sizeof(elfhdr));
+   if (!memcmp(hdrbuf, elfhdr, sizeof(elfhdr)))
+      return 0;
+
+   len = lseek(fd_in, 0, SEEK_END);
+   if (len < sizeof(IMAGE_DOS_HEADER))
+   {
+      close(fd_in);
+      printf("'%s' isn't a PE image (too short)\n", argv[1]);
+      return 1;
+   }
+
+   /* Lower down we overwrite the byte at len, so here, we need at least
+    * one more byte than len.  We'll be guaranteed one or two now. */
+   buffer = malloc((len + 2) & ~1);
+   if (buffer == NULL)
+   {
+      close(fd_in);
+      printf("Not enough memory available.\n");
+      return 1;
+   }
+
+   /* Read the whole input file into a buffer */
+   lseek(fd_in, 0, SEEK_SET);
+   read(fd_in, buffer, len);
+   /* Here is where the block end overwrite was */
+   if (len & 1)
+      buffer[len] = 0;
+
+   close(fd_in);
+
+   /*
+    * Check the headers and save pointers to them.
+    */
+
+   dos_header = (PIMAGE_DOS_HEADER)buffer;
+   nt_header = (PIMAGE_NT_HEADERS)(buffer + dtohl(dos_header->e_lfanew));
+
+   if (dtohs(dos_header->e_magic) != IMAGE_DOS_SIGNATURE ||
+       dtohl(nt_header->Signature) != IMAGE_NT_SIGNATURE)
+   {
+      printf("'%s' isn't a PE image (bad headers)\n", argv[1]);
+      free(buffer);
+      return 1;
+   }
+
+   if (fixup_exports)
+   {
+      /* Sort export directory */
+      data_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+      if (dtohl(data_dir->Size) != 0)
+      {
+         PIMAGE_EXPORT_DIRECTORY export_directory;
+         DWORD *name_ptr;
+         WORD *ordinal_ptr;
+         export_t *exports;
+
+         export_directory = (PIMAGE_EXPORT_DIRECTORY)rva_to_ptr(dtohl(data_dir->VirtualAddress));
+         if (export_directory != NULL)
+         {
+            exports = malloc(sizeof(export_t) * dtohl(export_directory->NumberOfNames));
+            if (exports == NULL)
+            {
+               printf("Not enough memory.\n");
+               free(buffer);
+               return 1;
+            }
+
+            name_ptr = (DWORD *)rva_to_ptr(dtohl(export_directory->AddressOfNames));
+            ordinal_ptr = (WORD *)rva_to_ptr(dtohl(export_directory->AddressOfNameOrdinals));
+
+            for (i = 0; i < dtohl(export_directory->NumberOfNames); i++)
+            {
+               exports[i].name = dtohl(name_ptr[i]);
+               exports[i].ordinal = dtohl(ordinal_ptr[i]);
+            }
+
+            qsort(exports, dtohl(export_directory->NumberOfNames), sizeof(export_t),
+                  export_compare_func);
+
+            for (i = 0; i < dtohl(export_directory->NumberOfNames); i++)
+            {
+               name_ptr[i] = htodl(exports[i].name);
+               ordinal_ptr[i] = htodl(exports[i].ordinal);
+            }
+
+            free(exports);
+         }
+      }
+   }
+
+   if (fixup_sections)
+   {
+      /* Update section flags */
+      for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);
+           i < dtohl(nt_header->OptionalHeader.NumberOfRvaAndSizes);
+           i++, section_header++)
+      {
+         if (!strcmp((char*)section_header->Name, ".text") ||
+             !strcmp((char*)section_header->Name, ".data") ||
+             !strcmp((char*)section_header->Name, ".idata") ||
+             !strcmp((char*)section_header->Name, ".bss"))
+         {
+            section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED);
+            section_header->Characteristics &= htodl(~IMAGE_SCN_MEM_DISCARDABLE);
+         }
+         else if (!strcmp((char*)section_header->Name, "INIT"))
+         {
+            section_header->Characteristics |= htodl(IMAGE_SCN_MEM_DISCARDABLE);
+         }
+         else if (!strcmp((char*)section_header->Name, "PAGE"))
+         {
+            section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED);
+         }
+      }
+   }
+
+   /* Recalculate checksum */
+   nt_header->OptionalHeader.CheckSum = 0;
+   checksum = 0;
+   for (i = 0; i < len; i += 2)
+   {
+      checksum += *(unsigned short *)(buffer + i);
+      checksum = (checksum + (checksum >> 16)) & 0xffff;
+   }
+   checksum += len;
+   nt_header->OptionalHeader.CheckSum = htods(checksum);
+
+   /* Write the output file */
+   fd_out = open(argv[1], O_WRONLY | O_BINARY);
+   write(fd_out, buffer, len);
+   close(fd_out);
+
+   return 0;
+}