Add new PEFIXUP tool and use it in the build system.

svn path=/trunk/; revision=16960
This commit is contained in:
Filip Navara 2005-08-01 17:56:41 +00:00
parent 0c3b9e8545
commit 28aff5352b
4 changed files with 416 additions and 1 deletions

374
reactos/tools/pefixup.c Normal file
View file

@ -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_HEADERS)(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;
}

36
reactos/tools/pefixup.mak Normal file
View file

@ -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

View 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 () );

View 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