Skip to content

Commit 56c4611

Browse files
committedJan 26, 2014
[PECOFF] Emit PE32+ file header.
llvm-svn: 200128
1 parent a302d29 commit 56c4611

File tree

3 files changed

+123
-24
lines changed

3 files changed

+123
-24
lines changed
 

‎lld/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp

+38-24
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class DOSStubChunk : public HeaderChunk {
123123
};
124124

125125
/// A PEHeaderChunk represents PE header including COFF header.
126+
template <class PEHeader>
126127
class PEHeaderChunk : public HeaderChunk {
127128
public:
128129
explicit PEHeaderChunk(const PECOFFLinkingContext &ctx);
@@ -136,7 +137,7 @@ class PEHeaderChunk : public HeaderChunk {
136137

137138
void setSizeOfCode(uint64_t size) { _peHeader.SizeOfCode = size; }
138139
void setBaseOfCode(uint32_t rva) { _peHeader.BaseOfCode = rva; }
139-
void setBaseOfData(uint32_t rva) { _peHeader.BaseOfData = rva; }
140+
void setBaseOfData(uint32_t rva);
140141
void setSizeOfImage(uint32_t size) { _peHeader.SizeOfImage = size; }
141142

142143
void setSizeOfInitializedData(uint64_t size) {
@@ -155,7 +156,7 @@ class PEHeaderChunk : public HeaderChunk {
155156

156157
private:
157158
llvm::object::coff_file_header _coffHeader;
158-
llvm::object::pe32_header _peHeader;
159+
PEHeader _peHeader;
159160
};
160161

161162
/// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
@@ -310,7 +311,8 @@ class BaseRelocChunk : public SectionChunk {
310311
std::vector<uint8_t> _contents;
311312
};
312313

313-
PEHeaderChunk::PEHeaderChunk(const PECOFFLinkingContext &ctx)
314+
template <class PEHeader>
315+
PEHeaderChunk<PEHeader>::PEHeaderChunk(const PECOFFLinkingContext &ctx)
314316
: HeaderChunk() {
315317
// Set the size of the chunk and initialize the header with null bytes.
316318
_size = sizeof(llvm::COFF::PEMagic) + sizeof(_coffHeader) + sizeof(_peHeader);
@@ -400,7 +402,18 @@ PEHeaderChunk::PEHeaderChunk(const PECOFFLinkingContext &ctx)
400402
_peHeader.NumberOfRvaAndSize = 16;
401403
}
402404

403-
void PEHeaderChunk::write(uint8_t *buffer) {
405+
template <>
406+
void PEHeaderChunk<llvm::object::pe32_header>::setBaseOfData(uint32_t rva) {
407+
_peHeader.BaseOfData = rva;
408+
}
409+
410+
template <>
411+
void PEHeaderChunk<llvm::object::pe32plus_header>::setBaseOfData(uint32_t rva) {
412+
// BaseOfData field does not exist in PE32+ header.
413+
}
414+
415+
template <class PEHeader>
416+
void PEHeaderChunk<PEHeader>::write(uint8_t *buffer) {
404417
std::memcpy(buffer, llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic));
405418
buffer += sizeof(llvm::COFF::PEMagic);
406419
std::memcpy(buffer, &_coffHeader, sizeof(_coffHeader));
@@ -742,7 +755,7 @@ class PECOFFWriter : public Writer {
742755
: _ctx(context), _numSections(0), _imageSizeInMemory(PAGE_SIZE),
743756
_imageSizeOnDisk(0) {}
744757

745-
void build(const File &linkedFile);
758+
template <class PEHeader> void build(const File &linkedFile);
746759
virtual error_code writeFile(const File &linkedFile, StringRef path);
747760

748761
private:
@@ -751,7 +764,6 @@ class PECOFFWriter : public Writer {
751764
void addChunk(Chunk *chunk);
752765
void addSectionChunk(SectionChunk *chunk, SectionHeaderTableChunk *table);
753766
void setImageSizeOnDisk();
754-
void setAddressOfEntryPoint(AtomChunk *text, PEHeaderChunk *peHeader);
755767
uint64_t
756768
calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
757769

@@ -829,13 +841,14 @@ void groupAtoms(const PECOFFLinkingContext &ctx, const File &file,
829841
}
830842

831843
// Create all chunks that consist of the output file.
844+
template <class PEHeader>
832845
void PECOFFWriter::build(const File &linkedFile) {
833846
AtomVectorMap atoms;
834847
groupAtoms(_ctx, linkedFile, atoms);
835848

836849
// Create file chunks and add them to the list.
837850
auto *dosStub = new DOSStubChunk(_ctx);
838-
auto *peHeader = new PEHeaderChunk(_ctx);
851+
auto *peHeader = new PEHeaderChunk<PEHeader>(_ctx);
839852
auto *dataDirectory = new DataDirectoryChunk();
840853
auto *sectionTable = new SectionHeaderTableChunk();
841854
addChunk(dosStub);
@@ -871,7 +884,19 @@ void PECOFFWriter::build(const File &linkedFile) {
871884
continue;
872885
if (section->getSectionName() == ".text") {
873886
peHeader->setBaseOfCode(section->getVirtualAddress());
874-
setAddressOfEntryPoint(dyn_cast<AtomChunk>(section), peHeader);
887+
888+
// Find the virtual address of the entry point symbol if any. PECOFF spec
889+
// says that entry point for dll images is optional, in which case it must
890+
// be set to 0.
891+
if (_ctx.entrySymbolName().empty() && _ctx.isDll()) {
892+
peHeader->setAddressOfEntryPoint(0);
893+
} else {
894+
uint64_t entryPointAddress =
895+
dyn_cast<AtomChunk>(section)
896+
->getAtomVirtualAddress(_ctx.entrySymbolName());
897+
if (entryPointAddress != 0)
898+
peHeader->setAddressOfEntryPoint(entryPointAddress);
899+
}
875900
}
876901
if (section->getSectionName() == ".data")
877902
peHeader->setBaseOfData(section->getVirtualAddress());
@@ -897,7 +922,11 @@ void PECOFFWriter::build(const File &linkedFile) {
897922
}
898923

899924
error_code PECOFFWriter::writeFile(const File &linkedFile, StringRef path) {
900-
this->build(linkedFile);
925+
if (_ctx.is64Bit()) {
926+
this->build<llvm::object::pe32plus_header>(linkedFile);
927+
} else {
928+
this->build<llvm::object::pe32_header>(linkedFile);
929+
}
901930

902931
uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
903932
OwningPtr<llvm::FileOutputBuffer> buffer;
@@ -977,21 +1006,6 @@ void PECOFFWriter::setImageSizeOnDisk() {
9771006
}
9781007
}
9791008

980-
void PECOFFWriter::setAddressOfEntryPoint(AtomChunk *text,
981-
PEHeaderChunk *peHeader) {
982-
// Find the virtual address of the entry point symbol if any.
983-
// PECOFF spec says that entry point for dll images is optional, in which
984-
// case it must be set to 0.
985-
if (_ctx.entrySymbolName().empty() && _ctx.isDll()) {
986-
peHeader->setAddressOfEntryPoint(0);
987-
} else {
988-
uint64_t entryPointAddress =
989-
text->getAtomVirtualAddress(_ctx.entrySymbolName());
990-
if (entryPointAddress != 0)
991-
peHeader->setAddressOfEntryPoint(entryPointAddress);
992-
}
993-
}
994-
9951009
uint64_t PECOFFWriter::calcSectionSize(
9961010
llvm::COFF::SectionCharacteristics sectionType) const {
9971011
uint64_t ret = 0;

‎lld/test/pecoff/Inputs/nop64.obj

416 Bytes
Binary file not shown.

‎lld/test/pecoff/peplus.test

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# RUN: lld -flavor link /out:%t.exe /subsystem:console /machine:x64 \
2+
# RUN: /entry:start -- %p/Inputs/nop64.obj
3+
# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
4+
5+
CHECK: Format: COFF-x86-64
6+
CHECK-NEXT: Arch: x86_64
7+
CHECK-NEXT: AddressSize: 64bit
8+
CHECK-NEXT: ImageFileHeader {
9+
CHECK-NEXT: Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664)
10+
CHECK-NEXT: SectionCount: 3
11+
CHECK-NEXT: TimeDateStamp:
12+
CHECK-NEXT: PointerToSymbolTable: 0x0
13+
CHECK-NEXT: SymbolCount: 0
14+
CHECK-NEXT: OptionalHeaderSize: 224
15+
CHECK-NEXT: Characteristics [ (0x102)
16+
CHECK-NEXT: IMAGE_FILE_32BIT_MACHINE (0x100)
17+
CHECK-NEXT: IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
18+
CHECK-NEXT: ]
19+
CHECK-NEXT: }
20+
CHECK-NEXT: ImageOptionalHeader {
21+
CHECK-NEXT: MajorLinkerVersion: 0
22+
CHECK-NEXT: MinorLinkerVersion: 0
23+
CHECK-NEXT: SizeOfCode: 1
24+
CHECK-NEXT: SizeOfInitializedData: 108
25+
CHECK-NEXT: SizeOfUninitializedData: 0
26+
CHECK-NEXT: AddressOfEntryPoint: 0x2000
27+
CHECK-NEXT: BaseOfCode: 0x2000
28+
CHECK-NEXT: ImageBase: 0x400000
29+
CHECK-NEXT: SectionAlignment: 4096
30+
CHECK-NEXT: FileAlignment: 512
31+
CHECK-NEXT: MajorOperatingSystemVersion: 6
32+
CHECK-NEXT: MinorOperatingSystemVersion: 0
33+
CHECK-NEXT: MajorImageVersion: 0
34+
CHECK-NEXT: MinorImageVersion: 0
35+
CHECK-NEXT: MajorSubsystemVersion: 6
36+
CHECK-NEXT: MinorSubsystemVersion: 0
37+
CHECK-NEXT: SizeOfImage: 12288
38+
CHECK-NEXT: SizeOfHeaders: 512
39+
CHECK-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
40+
CHECK-NEXT: Subsystem [ (0x8540)
41+
CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
42+
CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_SEH (0x400)
43+
CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
44+
CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
45+
CHECK-NEXT: ]
46+
CHECK-NEXT: SizeOfStackReserve: 1048576
47+
CHECK-NEXT: SizeOfStackCommit: 4096
48+
CHECK-NEXT: SizeOfHeapReserve: 1048576
49+
CHECK-NEXT: SizeOfHeapCommit: 4096
50+
CHECK-NEXT: NumberOfRvaAndSize: 16
51+
CHECK-NEXT: DataDirectory {
52+
CHECK-NEXT: ExportTableRVA: 0x0
53+
CHECK-NEXT: ExportTableSize: 0x0
54+
CHECK-NEXT: ImportTableRVA: 0x0
55+
CHECK-NEXT: ImportTableSize: 0x0
56+
CHECK-NEXT: ResourceTableRVA: 0x0
57+
CHECK-NEXT: ResourceTableSize: 0x0
58+
CHECK-NEXT: ExceptionTableRVA: 0x0
59+
CHECK-NEXT: ExceptionTableSize: 0x0
60+
CHECK-NEXT: CertificateTableRVA: 0x0
61+
CHECK-NEXT: CertificateTableSize: 0x0
62+
CHECK-NEXT: BaseRelocationTableRVA: 0x0
63+
CHECK-NEXT: BaseRelocationTableSize: 0x0
64+
CHECK-NEXT: DebugRVA: 0x0
65+
CHECK-NEXT: DebugSize: 0x0
66+
CHECK-NEXT: ArchitectureRVA: 0x0
67+
CHECK-NEXT: ArchitectureSize: 0x0
68+
CHECK-NEXT: GlobalPtrRVA: 0x0
69+
CHECK-NEXT: GlobalPtrSize: 0x0
70+
CHECK-NEXT: TLSTableRVA: 0x0
71+
CHECK-NEXT: TLSTableSize: 0x0
72+
CHECK-NEXT: LoadConfigTableRVA: 0x0
73+
CHECK-NEXT: LoadConfigTableSize: 0x0
74+
CHECK-NEXT: BoundImportRVA: 0x0
75+
CHECK-NEXT: BoundImportSize: 0x0
76+
CHECK-NEXT: IATRVA: 0x0
77+
CHECK-NEXT: IATSize: 0x0
78+
CHECK-NEXT: DelayImportDescriptorRVA: 0x0
79+
CHECK-NEXT: DelayImportDescriptorSize: 0x0
80+
CHECK-NEXT: CLRRuntimeHeaderRVA: 0x0
81+
CHECK-NEXT: CLRRuntimeHeaderSize: 0x0
82+
CHECK-NEXT: ReservedRVA: 0x0
83+
CHECK-NEXT: ReservedSize: 0x0
84+
CHECK-NEXT: }
85+
CHECK-NEXT: }

0 commit comments

Comments
 (0)