Skip to content

Commit

Permalink
llvm-readobj: add support for PE32+ (Windows 64 bit executable).
Browse files Browse the repository at this point in the history
PE32+ supports 64 bit address space, but the file format remains 32 bit.
So its file format is pretty similar to PE32 (32 bit executable). The
differences compared to PE32 are (1) the lack of "BaseOfData" field and
(2) some of its data members are 64 bit.

In this patch, I added a new member function to get a PE32+ Header object to
COFFObjectFile class and made llvm-readobj to use it.

llvm-svn: 200117
  • Loading branch information
rui314 committed Jan 26, 2014
1 parent e52d556 commit 10ed9dd
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 62 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/Object/COFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ class COFFObjectFile : public ObjectFile {
friend class ExportDirectoryEntryRef;
const coff_file_header *COFFHeader;
const pe32_header *PE32Header;
const pe32plus_header *PE32PlusHeader;
const data_directory *DataDirectory;
const coff_section *SectionTable;
const coff_symbol *SymbolTable;
Expand Down Expand Up @@ -347,6 +348,7 @@ class COFFObjectFile : public ObjectFile {
error_code getHeader(const coff_file_header *&Res) const;
error_code getCOFFHeader(const coff_file_header *&Res) const;
error_code getPE32Header(const pe32_header *&Res) const;
error_code getPE32PlusHeader(const pe32plus_header *&Res) const;
error_code getDataDirectory(uint32_t index, const data_directory *&Res) const;
error_code getSection(int32_t index, const coff_section *&Res) const;
error_code getSymbol(uint32_t index, const coff_symbol *&Res) const;
Expand Down
47 changes: 33 additions & 14 deletions llvm/lib/Object/COFFObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,8 @@ error_code COFFObjectFile::initExportTablePtr() {
COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &EC,
bool BufferOwned)
: ObjectFile(Binary::ID_COFF, Object, BufferOwned), COFFHeader(0),
PE32Header(0), DataDirectory(0), SectionTable(0), SymbolTable(0),
StringTable(0), StringTableSize(0), ImportDirectory(0),
PE32Header(0), PE32PlusHeader(0), DataDirectory(0), SectionTable(0),
SymbolTable(0), StringTable(0), StringTableSize(0), ImportDirectory(0),
NumberOfImportDirectory(0), ExportDirectory(0) {
// Check that we at least have enough room for a header.
if (!checkSize(Data, EC, sizeof(coff_file_header))) return;
Expand Down Expand Up @@ -499,19 +499,27 @@ COFFObjectFile::COFFObjectFile(MemoryBuffer *Object, error_code &EC,
CurPtr += sizeof(coff_file_header);

if (HasPEHeader) {
if ((EC = getObject(PE32Header, Data, base() + CurPtr)))
const pe32_header *Header;
if ((EC = getObject(Header, Data, base() + CurPtr)))
return;

const uint8_t *DataDirAddr;
uint64_t DataDirSize;
if (Header->Magic == 0x10b) {
PE32Header = Header;
DataDirAddr = base() + CurPtr + sizeof(pe32_header);
DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
} else if (Header->Magic == 0x20b) {
PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
} else {
// It's neither PE32 nor PE32+.
EC = object_error::parse_failed;
return;
if (PE32Header->Magic != 0x10b) {
// We only support PE32. If this is PE32 (not PE32+), the magic byte
// should be 0x10b. If this is not PE32, continue as if there's no PE
// header in this file.
PE32Header = 0;
} else if (PE32Header->NumberOfRvaAndSize > 0) {
const uint8_t *Addr = base() + CurPtr + sizeof(pe32_header);
uint64_t size = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
if ((EC = getObject(DataDirectory, Data, Addr, size)))
return;
}
if ((EC = getObject(DataDirectory, Data, DataDirAddr, DataDirSize)))
return;
CurPtr += COFFHeader->SizeOfOptionalHeader;
}

Expand Down Expand Up @@ -655,10 +663,21 @@ error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const {
return object_error::success;
}

error_code
COFFObjectFile::getPE32PlusHeader(const pe32plus_header *&Res) const {
Res = PE32PlusHeader;
return object_error::success;
}

error_code COFFObjectFile::getDataDirectory(uint32_t Index,
const data_directory *&Res) const {
// Error if if there's no data directory or the index is out of range.
if (!DataDirectory || Index > PE32Header->NumberOfRvaAndSize)
if (!DataDirectory)
return object_error::parse_failed;
assert(PE32Header || PE32PlusHeader);
uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
: PE32PlusHeader->NumberOfRvaAndSize;
if (Index > NumEnt)
return object_error::parse_failed;
Res = &DataDirectory[Index];
return object_error::success;
Expand Down
Binary file not shown.
82 changes: 82 additions & 0 deletions llvm/test/tools/llvm-readobj/peplus.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
RUN: llvm-readobj -file-headers %p/Inputs/nop.exe.coff-x86-64 | FileCheck %s

CHECK: Format: COFF-x86-64
CHECK: Arch: x86_64
CHECK: AddressSize: 64bit
CHECK: ImageFileHeader {
CHECK: Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664)
CHECK: SectionCount: 1
CHECK: TimeDateStamp: 2014-01-26 03:43:56 (0x52E4847C)
CHECK: PointerToSymbolTable: 0x0
CHECK: SymbolCount: 0
CHECK: OptionalHeaderSize: 240
CHECK: Characteristics [ (0x22)
CHECK: IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
CHECK: IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20)
CHECK: ]
CHECK: }
CHECK: ImageOptionalHeader {
CHECK: MajorLinkerVersion: 11
CHECK: MinorLinkerVersion: 0
CHECK: SizeOfCode: 512
CHECK: SizeOfInitializedData: 0
CHECK: SizeOfUninitializedData: 0
CHECK: AddressOfEntryPoint: 0x1000
CHECK: BaseOfCode: 0x1000
CHECK: ImageBase: 0x140000000
CHECK: SectionAlignment: 4096
CHECK: FileAlignment: 512
CHECK: MajorOperatingSystemVersion: 6
CHECK: MinorOperatingSystemVersion: 0
CHECK: MajorImageVersion: 0
CHECK: MinorImageVersion: 0
CHECK: MajorSubsystemVersion: 6
CHECK: MinorSubsystemVersion: 0
CHECK: SizeOfImage: 8192
CHECK: SizeOfHeaders: 512
CHECK: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
CHECK: Subsystem [ (0x8160)
CHECK: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
CHECK: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
CHECK: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
CHECK: ]
CHECK: SizeOfStackReserve: 1048576
CHECK: SizeOfStackCommit: 4096
CHECK: SizeOfHeapReserve: 1048576
CHECK: SizeOfHeapCommit: 4096
CHECK: NumberOfRvaAndSize: 16
CHECK: DataDirectory {
CHECK: ExportTableRVA: 0x0
CHECK: ExportTableSize: 0x0
CHECK: ImportTableRVA: 0x0
CHECK: ImportTableSize: 0x0
CHECK: ResourceTableRVA: 0x0
CHECK: ResourceTableSize: 0x0
CHECK: ExceptionTableRVA: 0x0
CHECK: ExceptionTableSize: 0x0
CHECK: CertificateTableRVA: 0x0
CHECK: CertificateTableSize: 0x0
CHECK: BaseRelocationTableRVA: 0x0
CHECK: BaseRelocationTableSize: 0x0
CHECK: DebugRVA: 0x0
CHECK: DebugSize: 0x0
CHECK: ArchitectureRVA: 0x0
CHECK: ArchitectureSize: 0x0
CHECK: GlobalPtrRVA: 0x0
CHECK: GlobalPtrSize: 0x0
CHECK: TLSTableRVA: 0x0
CHECK: TLSTableSize: 0x0
CHECK: LoadConfigTableRVA: 0x0
CHECK: LoadConfigTableSize: 0x0
CHECK: BoundImportRVA: 0x0
CHECK: BoundImportSize: 0x0
CHECK: IATRVA: 0x0
CHECK: IATSize: 0x0
CHECK: DelayImportDescriptorRVA: 0x0
CHECK: DelayImportDescriptorSize: 0x0
CHECK: CLRRuntimeHeaderRVA: 0x0
CHECK: CLRRuntimeHeaderSize: 0x0
CHECK: ReservedRVA: 0x0
CHECK: ReservedSize: 0x0
CHECK: }
CHECK: }
111 changes: 63 additions & 48 deletions llvm/tools/llvm-readobj/COFFDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ class COFFDumper : public ObjDumper {

private:
void printSymbol(symbol_iterator SymI);

void printRelocation(section_iterator SecI, relocation_iterator RelI);

void printDataDirectory(uint32_t Index, const std::string &FieldName);

void printX64UnwindInfo();

template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
void printBaseOfDataField(const pe32_header *Hdr);
void printBaseOfDataField(const pe32plus_header *Hdr);

void printRuntimeFunction(
const RuntimeFunction& RTF,
uint64_t OffsetInSection,
Expand Down Expand Up @@ -599,56 +600,70 @@ void COFFDumper::printFileHeaders() {
const pe32_header *PEHeader = 0;
if (error(Obj->getPE32Header(PEHeader)))
return;
if (PEHeader)
printPEHeader<pe32_header>(PEHeader);

if (PEHeader) {
DictScope D(W, "ImageOptionalHeader");
W.printNumber("MajorLinkerVersion", PEHeader->MajorLinkerVersion);
W.printNumber("MinorLinkerVersion", PEHeader->MinorLinkerVersion);
W.printNumber("SizeOfCode", PEHeader->SizeOfCode);
W.printNumber("SizeOfInitializedData", PEHeader->SizeOfInitializedData);
W.printNumber("SizeOfUninitializedData", PEHeader->SizeOfUninitializedData);
W.printHex ("AddressOfEntryPoint", PEHeader->AddressOfEntryPoint);
W.printHex ("BaseOfCode", PEHeader->BaseOfCode);
W.printHex ("BaseOfData", PEHeader->BaseOfData);
W.printHex ("ImageBase", PEHeader->ImageBase);
W.printNumber("SectionAlignment", PEHeader->SectionAlignment);
W.printNumber("FileAlignment", PEHeader->FileAlignment);
W.printNumber("MajorOperatingSystemVersion",
PEHeader->MajorOperatingSystemVersion);
W.printNumber("MinorOperatingSystemVersion",
PEHeader->MinorOperatingSystemVersion);
W.printNumber("MajorImageVersion", PEHeader->MajorImageVersion);
W.printNumber("MinorImageVersion", PEHeader->MinorImageVersion);
W.printNumber("MajorSubsystemVersion", PEHeader->MajorSubsystemVersion);
W.printNumber("MinorSubsystemVersion", PEHeader->MinorSubsystemVersion);
W.printNumber("SizeOfImage", PEHeader->SizeOfImage);
W.printNumber("SizeOfHeaders", PEHeader->SizeOfHeaders);
W.printEnum ("Subsystem", PEHeader->Subsystem,
makeArrayRef(PEWindowsSubsystem));
W.printFlags ("Subsystem", PEHeader->DLLCharacteristics,
makeArrayRef(PEDLLCharacteristics));
W.printNumber("SizeOfStackReserve", PEHeader->SizeOfStackReserve);
W.printNumber("SizeOfStackCommit", PEHeader->SizeOfStackCommit);
W.printNumber("SizeOfHeapReserve", PEHeader->SizeOfHeapReserve);
W.printNumber("SizeOfHeapCommit", PEHeader->SizeOfHeapCommit);
W.printNumber("NumberOfRvaAndSize", PEHeader->NumberOfRvaAndSize);

if (PEHeader->NumberOfRvaAndSize > 0) {
DictScope D(W, "DataDirectory");
static const char * const directory[] = {
"ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
"CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
"GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
"DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
};

for (uint32_t i = 0; i < PEHeader->NumberOfRvaAndSize; ++i) {
printDataDirectory(i, directory[i]);
}
const pe32plus_header *PEPlusHeader = 0;
if (error(Obj->getPE32PlusHeader(PEPlusHeader)))
return;
if (PEPlusHeader)
printPEHeader<pe32plus_header>(PEPlusHeader);
}

template <class PEHeader>
void COFFDumper::printPEHeader(const PEHeader *Hdr) {
DictScope D(W, "ImageOptionalHeader");
W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion);
W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion);
W.printNumber("SizeOfCode", Hdr->SizeOfCode);
W.printNumber("SizeOfInitializedData", Hdr->SizeOfInitializedData);
W.printNumber("SizeOfUninitializedData", Hdr->SizeOfUninitializedData);
W.printHex ("AddressOfEntryPoint", Hdr->AddressOfEntryPoint);
W.printHex ("BaseOfCode", Hdr->BaseOfCode);
printBaseOfDataField(Hdr);
W.printHex ("ImageBase", Hdr->ImageBase);
W.printNumber("SectionAlignment", Hdr->SectionAlignment);
W.printNumber("FileAlignment", Hdr->FileAlignment);
W.printNumber("MajorOperatingSystemVersion",
Hdr->MajorOperatingSystemVersion);
W.printNumber("MinorOperatingSystemVersion",
Hdr->MinorOperatingSystemVersion);
W.printNumber("MajorImageVersion", Hdr->MajorImageVersion);
W.printNumber("MinorImageVersion", Hdr->MinorImageVersion);
W.printNumber("MajorSubsystemVersion", Hdr->MajorSubsystemVersion);
W.printNumber("MinorSubsystemVersion", Hdr->MinorSubsystemVersion);
W.printNumber("SizeOfImage", Hdr->SizeOfImage);
W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
W.printFlags ("Subsystem", Hdr->DLLCharacteristics,
makeArrayRef(PEDLLCharacteristics));
W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
W.printNumber("SizeOfHeapCommit", Hdr->SizeOfHeapCommit);
W.printNumber("NumberOfRvaAndSize", Hdr->NumberOfRvaAndSize);

if (Hdr->NumberOfRvaAndSize > 0) {
DictScope D(W, "DataDirectory");
static const char * const directory[] = {
"ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
"CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
"GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
"DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
};

for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) {
printDataDirectory(i, directory[i]);
}
}
}

void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
W.printHex("BaseOfData", Hdr->BaseOfData);
}

void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}

void COFFDumper::printCodeViewLineTables(section_iterator SecI) {
StringRef Data;
if (error(SecI->getContents(Data))) return;
Expand Down

0 comments on commit 10ed9dd

Please sign in to comment.