Add new PEFIXUP tool and use it in the build system.
authorFilip Navara <filip.navara@gmail.com>
Mon, 1 Aug 2005 17:56:41 +0000 (17:56 +0000)
committerFilip Navara <filip.navara@gmail.com>
Mon, 1 Aug 2005 17:56:41 +0000 (17:56 +0000)
svn path=/trunk/; revision=16960

reactos/tools/pefixup.c [new file with mode: 0644]
reactos/tools/pefixup.mak [new file with mode: 0644]
reactos/tools/rbuild/backend/mingw/modulehandler.cpp
reactos/tools/tools.mak

diff --git a/reactos/tools/pefixup.c b/reactos/tools/pefixup.c
new file mode 100644 (file)
index 0000000..251722a
--- /dev/null
@@ -0,0 +1,374 @@
+/*\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 (section_header->VirtualAddress)\r
+        break;\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
diff --git a/reactos/tools/pefixup.mak b/reactos/tools/pefixup.mak
new file mode 100644 (file)
index 0000000..7f4aa79
--- /dev/null
@@ -0,0 +1,36 @@
+PEFIXUP_BASE = $(TOOLS_BASE)\r
+PEFIXUP_BASE_ = $(PEFIXUP_BASE)$(SEP)\r
+\r
+PEFIXUP_INT = $(INTERMEDIATE_)$(PEFIXUP_BASE)\r
+PEFIXUP_INT_ = $(PEFIXUP_INT)$(SEP)\r
+PEFIXUP_OUT = $(OUTPUT_)$(PEFIXUP_BASE)\r
+PEFIXUP_OUT_ = $(PEFIXUP_OUT)$(SEP)\r
+\r
+PEFIXUP_TARGET = \\r
+       $(EXEPREFIX)$(PEFIXUP_OUT_)pefixup$(EXEPOSTFIX)\r
+\r
+PEFIXUP_SOURCES = \\r
+       $(PEFIXUP_BASE_)pefixup.c\r
+\r
+PEFIXUP_OBJECTS = \\r
+       $(addprefix $(INTERMEDIATE_), $(PEFIXUP_SOURCES:.c=.o))\r
+\r
+PEFIXUP_HOST_CFLAGS = $(TOOLS_CFLAGS)\r
+\r
+PEFIXUP_HOST_LFLAGS = $(TOOLS_LFLAGS)\r
+\r
+.PHONY: pefixup\r
+pefixup: $(PEFIXUP_TARGET)\r
+\r
+$(PEFIXUP_TARGET): $(PEFIXUP_OBJECTS) | $(PEFIXUP_OUT)\r
+       $(ECHO_LD)\r
+       ${host_gcc} $(PEFIXUP_OBJECTS) $(PEFIXUP_HOST_LFLAGS) -o $@\r
+\r
+$(PEFIXUP_INT_)pefixup.o: $(PEFIXUP_BASE_)pefixup.c | $(PEFIXUP_INT)\r
+       $(ECHO_CC)\r
+       ${host_gcc} $(PEFIXUP_HOST_CFLAGS) -c $< -o $@\r
+\r
+.PHONY: pefixup_clean\r
+pefixup_clean:\r
+       -@$(rm) $(PEFIXUP_TARGET) $(PEFIXUP_OBJECTS) 2>$(NUL)\r
+clean: pefixup_clean\r
index 1db38f0..7b6a9e6 100644 (file)
@@ -1419,7 +1419,7 @@ MingwModuleHandler::GenerateLinkerCommand (
        string def_file = GetDefinitionFilename ();
 
        fprintf ( fMakefile,
-               "%s: %s %s $(RSYM_TARGET) | %s\n",
+               "%s: %s %s $(RSYM_TARGET) $(PEFIXUP_TARGET) | %s\n",
                target.c_str (),
                def_file.c_str (),
                dependencies.c_str (),
@@ -1450,6 +1450,10 @@ MingwModuleHandler::GenerateLinkerCommand (
                          libsMacro.c_str (),
                          GetLinkerMacro ().c_str () );
        
+               fprintf ( fMakefile,
+                         "\t$(Q)$(PEFIXUP_TARGET) %s -exports\n",
+                         target.c_str () );
+
                fprintf ( fMakefile,
                          "\t-@${rm} %s 2>$(NUL)\n",
                          temp_exp.c_str () );
index 0791b81..6676bc1 100644 (file)
@@ -22,6 +22,7 @@ endif
 
 include tools/bin2c.mak
 include tools/rsym.mak
+include tools/pefixup.mak
 include tools/bin2res/bin2res.mak
 include tools/buildno/buildno.mak
 include tools/cabman/cabman.mak