Add new PEFIXUP tool and use it in the build system. Added: trunk/reactos/tools/pefixup.c Added: trunk/reactos/tools/pefixup.mak Modified: trunk/reactos/tools/rbuild/backend/mingw/modulehandler.cpp Modified: trunk/reactos/tools/tools.mak _____
Added: trunk/reactos/tools/pefixup.c --- trunk/reactos/tools/pefixup.c 2005-08-01 16:28:11 UTC (rev 16959) +++ trunk/reactos/tools/pefixup.c 2005-08-01 17:56:41 UTC (rev 16960) @@ -0,0 +1,374 @@
+/* + * 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> + +/* 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; +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef int LONG; + +#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)&(((t*)0)->f)) +#define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((DWORD)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEAD ERS)(h))->FileHeader.SizeOfOptionalHeader)) +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 + +#pragma pack(push,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(pop) +#pragma pack(push,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(pop) + +/* 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; + +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 < nt_header->OptionalHeader.NumberOfRvaAndSizes; + i++, section_header++) + { + if (rva >= section_header->VirtualAddress && + rva < section_header->VirtualAddress + + section_header->Misc.VirtualSize) + { + return buffer + rva - section_header->VirtualAddress + + 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; + 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; + } + + len = lseek(fd_in, 0, SEEK_END); + if (len < sizeof(IMAGE_DOS_HEADER)) + { + close(fd_in); + printf("'%s' isn't a PE image.\n", argv[1]); + return 1; + } + + buffer = malloc((len + 1) & ~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); + 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 + dos_header->e_lfanew); + + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE || + nt_header->Signature != IMAGE_NT_SIGNATURE) + { + printf("'%s' isn't a PE image.\n", argv[1]); + free(buffer); + return 1; + } + + if (fixup_exports) + { + /* Sort export directory */ + data_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (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(data_dir->VirtualAddress); + if (export_directory != NULL) + { + exports = malloc(sizeof(export_t) * export_directory->NumberOfNames); + if (exports == NULL) + { + printf("Not enough memory.\n"); + free(buffer); + return 1; + } + + name_ptr = (DWORD *)rva_to_ptr(export_directory->AddressOfNames); + ordinal_ptr = (WORD *)rva_to_ptr(export_directory->AddressOfNameOrdinals); + + for (i = 0; i < export_directory->NumberOfNames; i++) + { + exports[i].name = name_ptr[i]; + exports[i].ordinal = ordinal_ptr[i]; + } + + qsort(exports, export_directory->NumberOfNames, sizeof(export_t), + export_compare_func); + + for (i = 0; i < export_directory->NumberOfNames; i++) + { + name_ptr[i] = exports[i].name; + ordinal_ptr[i] = exports[i].ordinal; + } + + free(exports); + } + } + } + + if (fixup_sections) + { + /* Update section flags */ + for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header); + i < nt_header->OptionalHeader.NumberOfRvaAndSizes; + i++, section_header++) + { + if (section_header->VirtualAddress) + break; + + if (!strcmp(section_header->Name, ".text") || + !strcmp(section_header->Name, ".data") || + !strcmp(section_header->Name, ".idata") || + !strcmp(section_header->Name, ".bss")) + { + section_header->Characteristics |= IMAGE_SCN_MEM_NOT_PAGED; + section_header->Characteristics &= ~IMAGE_SCN_MEM_DISCARDABLE; + } + else if (!strcmp(section_header->Name, "INIT")) + { + section_header->Characteristics |= IMAGE_SCN_MEM_DISCARDABLE; + } + else if (!strcmp(section_header->Name, "PAGE")) + { + section_header->Characteristics |= 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 = checksum; + + /* Write the output file */ + fd_out = open(argv[1], O_WRONLY | O_BINARY); + write(fd_out, buffer, len); + close(fd_out); + + return 0; +} _____
Added: trunk/reactos/tools/pefixup.mak --- trunk/reactos/tools/pefixup.mak 2005-08-01 16:28:11 UTC (rev 16959) +++ trunk/reactos/tools/pefixup.mak 2005-08-01 17:56:41 UTC (rev 16960) @@ -0,0 +1,36 @@
+PEFIXUP_BASE = $(TOOLS_BASE) +PEFIXUP_BASE_ = $(PEFIXUP_BASE)$(SEP) + +PEFIXUP_INT = $(INTERMEDIATE_)$(PEFIXUP_BASE) +PEFIXUP_INT_ = $(PEFIXUP_INT)$(SEP) +PEFIXUP_OUT = $(OUTPUT_)$(PEFIXUP_BASE) +PEFIXUP_OUT_ = $(PEFIXUP_OUT)$(SEP) + +PEFIXUP_TARGET = \ + $(EXEPREFIX)$(PEFIXUP_OUT_)pefixup$(EXEPOSTFIX) + +PEFIXUP_SOURCES = \ + $(PEFIXUP_BASE_)pefixup.c + +PEFIXUP_OBJECTS = \ + $(addprefix $(INTERMEDIATE_), $(PEFIXUP_SOURCES:.c=.o)) + +PEFIXUP_HOST_CFLAGS = $(TOOLS_CFLAGS) + +PEFIXUP_HOST_LFLAGS = $(TOOLS_LFLAGS) + +.PHONY: pefixup +pefixup: $(PEFIXUP_TARGET) + +$(PEFIXUP_TARGET): $(PEFIXUP_OBJECTS) | $(PEFIXUP_OUT) + $(ECHO_LD) + ${host_gcc} $(PEFIXUP_OBJECTS) $(PEFIXUP_HOST_LFLAGS) -o $@ + +$(PEFIXUP_INT_)pefixup.o: $(PEFIXUP_BASE_)pefixup.c | $(PEFIXUP_INT) + $(ECHO_CC) + ${host_gcc} $(PEFIXUP_HOST_CFLAGS) -c $< -o $@ + +.PHONY: pefixup_clean +pefixup_clean: + -@$(rm) $(PEFIXUP_TARGET) $(PEFIXUP_OBJECTS) 2>$(NUL) +clean: pefixup_clean _____
Modified: trunk/reactos/tools/rbuild/backend/mingw/modulehandler.cpp --- trunk/reactos/tools/rbuild/backend/mingw/modulehandler.cpp 2005-08-01 16:28:11 UTC (rev 16959) +++ trunk/reactos/tools/rbuild/backend/mingw/modulehandler.cpp 2005-08-01 17:56:41 UTC (rev 16960) @@ -1419,7 +1419,7 @@
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 (), @@ -1451,6 +1451,10 @@ 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 () ); } _____
Modified: trunk/reactos/tools/tools.mak --- trunk/reactos/tools/tools.mak 2005-08-01 16:28:11 UTC (rev 16959) +++ trunk/reactos/tools/tools.mak 2005-08-01 17:56:41 UTC (rev 16960) @@ -22,6 +22,7 @@
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