singrdk/base/boot/include/expandpe.cpp

378 lines
13 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// expandpe.cpp: code to expand PE image into memory.
//
//#define EXPANDPE_VERBOSE 1
///////////////////////////////////////////////// Required External Functions.
//
void CopyDown(UINT8 *pbDst, UINT8 *pbSrc, UINT32 cbSrc);
void Zero(uint8 * pbData, uint32 cbData);
//////////////////////////////////////////////////////////////////////////////
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
uint16 e_magic; // Magic number
uint16 e_cblp; // Bytes on last page of file
uint16 e_cp; // Pages in file
uint16 e_crlc; // Relocations
uint16 e_cparhdr; // Size of header in paragraphs
uint16 e_minalloc; // Minimum extra paragraphs needed
uint16 e_maxalloc; // Maximum extra paragraphs needed
uint16 e_ss; // Initial (relative) SS value
uint16 e_sp; // Initial SP value
uint16 e_csum; // Checksum
uint16 e_ip; // Initial IP value
uint16 e_cs; // Initial (relative) CS value
uint16 e_lfarlc; // File address of relocation table
uint16 e_ovno; // Overlay number
uint16 e_res[4]; // Reserved words
uint16 e_oemid; // OEM identifier (for e_oeminfo)
uint16 e_oeminfo; // OEM information; e_oemid specific
uint16 e_res2[10]; // Reserved words
uint32 e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_FILE_HEADER {
uint16 Machine;
uint16 NumberOfSections;
uint32 TimeDateStamp;
uint32 PointerToSymbolTable;
uint32 NumberOfSymbols;
uint16 SizeOfOptionalHeader;
uint16 Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
//
// Directory format.
//
typedef struct _IMAGE_DATA_DIRECTORY {
uint32 VirtualAddress;
uint32 Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
//
// Optional header format.
//
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
typedef struct _IMAGE_OPTIONAL_HEADER32 {
//
// Standard fields.
//
uint16 Magic;
uint8 MajorLinkerVersion;
uint8 MinorLinkerVersion;
uint32 SizeOfCode;
uint32 SizeOfInitializedData;
uint32 SizeOfUninitializedData;
uint32 AddressOfEntryPoint;
uint32 BaseOfCode;
uint32 BaseOfData;
//
// NT additional fields.
//
uint32 ImageBase;
uint32 SectionAlignment;
uint32 FileAlignment;
uint16 MajorOperatingSystemVersion;
uint16 MinorOperatingSystemVersion;
uint16 MajorImageVersion;
uint16 MinorImageVersion;
uint16 MajorSubsystemVersion;
uint16 MinorSubsystemVersion;
uint32 Win32VersionValue;
uint32 SizeOfImage;
uint32 SizeOfHeaders;
uint32 CheckSum;
uint16 Subsystem;
uint16 DllCharacteristics;
uint32 SizeOfStackReserve;
uint32 SizeOfStackCommit;
uint32 SizeOfHeapReserve;
uint32 SizeOfHeapCommit;
uint32 LoaderFlags;
uint32 NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
uint16 Magic;
uint8 MajorLinkerVersion;
uint8 MinorLinkerVersion;
uint32 SizeOfCode;
uint32 SizeOfInitializedData;
uint32 SizeOfUninitializedData;
uint32 AddressOfEntryPoint;
uint32 BaseOfCode;
uint64 ImageBase;
uint32 SectionAlignment;
uint32 FileAlignment;
uint16 MajorOperatingSystemVersion;
uint16 MinorOperatingSystemVersion;
uint16 MajorImageVersion;
uint16 MinorImageVersion;
uint16 MajorSubsystemVersion;
uint16 MinorSubsystemVersion;
uint32 Win32VersionValue;
uint32 SizeOfImage;
uint32 SizeOfHeaders;
uint32 CheckSum;
uint16 Subsystem;
uint16 DllCharacteristics;
uint64 SizeOfStackReserve;
uint64 SizeOfStackCommit;
uint64 SizeOfHeapReserve;
uint64 SizeOfHeapCommit;
uint32 LoaderFlags;
uint32 NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS64 {
uint32 Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
typedef struct _IMAGE_NT_HEADERS32 {
uint32 Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
uint8 Name[IMAGE_SIZEOF_SHORT_NAME];
uint32 VirtualSize;
uint32 VirtualAddress;
uint32 SizeOfRawData;
uint32 PointerToRawData;
uint32 PointerToRelocations;
uint32 PointerToLinenumbers;
uint16 NumberOfRelocations;
uint16 NumberOfLinenumbers;
uint32 Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
//
// Directory Entries
//
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
//
// Based relocation types.
//
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGH 1
#define IMAGE_REL_BASED_LOW 2
#define IMAGE_REL_BASED_HIGHLOW 3
#define IMAGE_REL_BASED_HIGHADJ 4
#define IMAGE_REL_BASED_MIPS_JMPADDR 5
#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
#define IMAGE_REL_BASED_IA64_IMM64 9
#define IMAGE_REL_BASED_DIR64 10
//////////////////////////////////////////////////////////////////////////////
//
uintptr SizeOfPeImage(uintptr source, uintptr& base)
{
UINT8 * pbImage = (UINT8 *)source;
uintptr size = 0;
IMAGE_DOS_HEADER * pidh = (IMAGE_DOS_HEADER *)pbImage;
if (pidh->e_magic != IMAGE_DOS_SIGNATURE) {
return 0;
}
IMAGE_NT_HEADERS32 * pinh = (IMAGE_NT_HEADERS32 *)(pbImage + pidh->e_lfanew);
IMAGE_NT_HEADERS64 * pinh64 = (IMAGE_NT_HEADERS64 *)(pbImage + pidh->e_lfanew);
if (pinh->Signature != IMAGE_NT_SIGNATURE) {
return 0;
}
if ((pinh->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) &&
(pinh64->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
return 0;
}
if (pinh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
base = pinh->OptionalHeader.ImageBase;
if (size < pinh->OptionalHeader.SizeOfHeaders) {
size = pinh->OptionalHeader.SizeOfHeaders;
}
}
else if (pinh64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
base = (uintptr)pinh64->OptionalHeader.ImageBase;
if (size < pinh->OptionalHeader.SizeOfHeaders) {
size = pinh->OptionalHeader.SizeOfHeaders;
}
}
else {
return 0;
}
IMAGE_SECTION_HEADER * pish = (IMAGE_SECTION_HEADER *)
(((uintptr)&pinh->OptionalHeader) + pinh->FileHeader.SizeOfOptionalHeader);
for (int i = 0; i < pinh->FileHeader.NumberOfSections; i++) {
uint8* pbDst = (uint8 *)base + pish[i].VirtualAddress;
uint8* pbSrc = pbImage + pish[i].PointerToRawData;
uint32 cbSrc = (pish[i].VirtualSize < pish[i].SizeOfRawData)
? pish[i].VirtualSize : pish[i].SizeOfRawData;
if (size < pish[i].VirtualAddress + pish[i].VirtualSize) {
size = pish[i].VirtualAddress + pish[i].VirtualSize;
}
}
return size;
}
uintptr ExpandPeImage(uintptr dst, uintptr src)
{
UINT8 * pbImage = (UINT8 *)src;
IMAGE_DOS_HEADER * pidh = (IMAGE_DOS_HEADER *)pbImage;
if (pidh->e_magic != IMAGE_DOS_SIGNATURE) {
printf("Mismatch MZ Signature: %04x != %04x\n",
pidh->e_magic, IMAGE_DOS_SIGNATURE);
return 0;
}
IMAGE_NT_HEADERS32 * pinh = (IMAGE_NT_HEADERS32 *)(pbImage + pidh->e_lfanew);
IMAGE_NT_HEADERS64 * pinh64 = (IMAGE_NT_HEADERS64 *)(pbImage + pidh->e_lfanew);
if (pinh->Signature != IMAGE_NT_SIGNATURE) {
printf("Mismatched NT Signature: %08x != %08x\n",
pinh->Signature, IMAGE_NT_SIGNATURE);
return 0;
}
if ((pinh->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) &&
(pinh64->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
printf("Mismatched PE Signature: %08x != %08x or %08x != %08x\n",
pinh->OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR32_MAGIC,
pinh64->OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR64_MAGIC);
return 0;
}
uintptr entry = 0;
uintptr diff = 0;
if (pinh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
diff = dst - pinh->OptionalHeader.ImageBase;
entry = dst + pinh->OptionalHeader.AddressOfEntryPoint;
CopyDown((uint8*)dst, pbImage, pinh->OptionalHeader.SizeOfHeaders);
}
else if (pinh64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
diff = dst - (uintptr)pinh64->OptionalHeader.ImageBase;
entry = dst + pinh64->OptionalHeader.AddressOfEntryPoint;
CopyDown((uint8*)dst, pbImage, pinh64->OptionalHeader.SizeOfHeaders);
}
else {
printf("Forgot to update IMAGE_NT_OPTIONAL test!\n");
return 0;
}
IMAGE_SECTION_HEADER * pish = (IMAGE_SECTION_HEADER *)
(((uintptr)&pinh->OptionalHeader) + pinh->FileHeader.SizeOfOptionalHeader);
#if EXPANDPE_VERBOSE
printf(" Section_ VirtAddr VirtSize _RawAddr _RawSize DestAddr CopySize SorcAddr\n");
#endif
for (int i = 0; i < pinh->FileHeader.NumberOfSections; i++) {
uint8* pbDst = (uint8 *)dst + pish[i].VirtualAddress;
uint8* pbSrc = pbImage + pish[i].PointerToRawData;
uint32 cbSrc = (pish[i].VirtualSize < pish[i].SizeOfRawData)
? pish[i].VirtualSize : pish[i].SizeOfRawData;
#if EXPANDPE_VERBOSE
printf(" %-8.8s %08x %8x %08x %8x %8x %8x %8x\n",
pish[i].Name,
pish[i].VirtualAddress,
pish[i].VirtualSize,
pish[i].PointerToRawData,
pish[i].SizeOfRawData,
pbDst,
cbSrc,
pbSrc);
#endif
Zero(pbDst, pish[i].VirtualSize);
CopyDown(pbDst, pbSrc, cbSrc);
}
// Process the relocations.
if (diff != 0) {
IMAGE_DATA_DIRECTORY * pidd
= &pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
uint8* pbReloc = (uint8*)dst + pidd->VirtualAddress;
uint8* pbRelocEnd = pbReloc + pidd->Size;
#if EXPANDPE_VERBOSE
printf("Relocs: %08x..%08x\n", pbReloc, pbRelocEnd);
#endif
while (pbReloc < pbRelocEnd) {
uint32 * ph = (uint32 *)pbReloc;
#if EXPANDPE_VERBOSE
printf(" %08x..%08x\n", ph[0], ph[1]);
#endif
uint16 * pr = (uint16 *)(pbReloc + 8);
uint16 * prEnd = (uint16 *)(pbReloc + ph[1]);
uintptr va = dst + ph[0];
for (; pr < prEnd; pr++) {
uintptr rva = va + (pr[0] & 0xfff);
switch (pr[0] >> 12) {
case IMAGE_REL_BASED_ABSOLUTE:
#if EXPANDPE_VERBOSE
printf(" %p: abs:%x\n", (uint32*)rva, *(uint32*)rva);
#endif
break;
case IMAGE_REL_BASED_HIGHLOW: // 32-bit reloc
#if EXPANDPE_VERBOSE
printf(" %p: r32:%x->%x\n",
(uint32*)rva, *(uint32*)rva, *(uint32*)rva + (uint32)diff);
#endif
*(uint32*)rva += (uint32)diff;
break;
case IMAGE_REL_BASED_DIR64: // 64-bit reloc
#if EXPANDPE_VERBOSE
printf(" %p: r64:%lx->%lx\n",
(uint64*)rva, *(uint64*)rva, *(uint64*)rva + (uint64)diff);
#endif
*(uint64*)rva += (uint64)diff;
break;
default:
printf("%p: %x --- Unknown relocation type!\n", (uint32*)rva, pr[0] >> 12);
return 0;
}
}
pbReloc = (uint8 *)prEnd;
}
}
return entry;
}
// End of File.