Skip to content

Commit 4902508

Browse files
committedApr 7, 2018
COFF: Process /merge flag as we create output sections.
With this we can merge builtin sections. Differential Revision: https://reviews.llvm.org/D45350 llvm-svn: 329471
1 parent 54fe208 commit 4902508

File tree

6 files changed

+95
-31
lines changed

6 files changed

+95
-31
lines changed
 

‎lld/COFF/DLL.h

+5
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ class EdataContents {
7676
public:
7777
EdataContents();
7878
std::vector<Chunk *> Chunks;
79+
80+
uint64_t getRVA() { return Chunks[0]->getRVA(); }
81+
uint64_t getSize() {
82+
return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
83+
}
7984
};
8085

8186
} // namespace coff

‎lld/COFF/DriverUtils.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ void parseMerge(StringRef S) {
185185
std::tie(From, To) = S.split('=');
186186
if (From.empty() || To.empty())
187187
fatal("/merge: invalid argument: " + S);
188+
if (From == ".rsrc" || To == ".rsrc")
189+
fatal("/merge: cannot merge '.rsrc' with any section");
190+
if (From == ".reloc" || To == ".reloc")
191+
fatal("/merge: cannot merge '.reloc' with any section");
188192
auto Pair = Config->Merge.insert(std::make_pair(From, To));
189193
bool Inserted = Pair.second;
190194
if (!Inserted) {

‎lld/COFF/Writer.cpp

+43-26
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,23 @@ class Writer {
209209
OutputSection *TextSec;
210210
OutputSection *RdataSec;
211211
OutputSection *DataSec;
212-
OutputSection *PdataSec;
213212
OutputSection *IdataSec;
214213
OutputSection *EdataSec;
215214
OutputSection *DidatSec;
216215
OutputSection *RsrcSec;
217216
OutputSection *RelocSec;
217+
218+
// The first and last .pdata sections in the output file.
219+
//
220+
// We need to keep track of the location of .pdata in whichever section it
221+
// gets merged into so that we can sort its contents and emit a correct data
222+
// directory entry for the exception table. This is also the case for some
223+
// other sections (such as .edata) but because the contents of those sections
224+
// are entirely linker-generated we can keep track of their locations using
225+
// the chunks that the linker creates. All .pdata chunks come from input
226+
// files, so we need to keep track of them separately.
227+
Chunk *FirstPdata = nullptr;
228+
Chunk *LastPdata;
218229
};
219230
} // anonymous namespace
220231

@@ -362,17 +373,12 @@ void Writer::run() {
362373
fatal("failed to write the output file: " + toString(std::move(E)));
363374
}
364375

365-
static StringRef getOutputSection(StringRef Name) {
376+
static StringRef getOutputSectionName(StringRef Name) {
366377
StringRef S = Name.split('$').first;
367378

368379
// Treat a later period as a separator for MinGW, for sections like
369380
// ".ctors.01234".
370-
S = S.substr(0, S.find('.', 1));
371-
372-
auto It = Config->Merge.find(S);
373-
if (It == Config->Merge.end())
374-
return S;
375-
return It->second;
381+
return S.substr(0, S.find('.', 1));
376382
}
377383

378384
// For /order.
@@ -403,10 +409,15 @@ void Writer::createSections() {
403409

404410
SmallDenseMap<StringRef, OutputSection *> Sections;
405411
auto CreateSection = [&](StringRef Name, uint32_t Perms) {
406-
auto Sec = make<OutputSection>(Name);
412+
auto I = Config->Merge.find(Name);
413+
if (I != Config->Merge.end())
414+
Name = I->second;
415+
OutputSection *&Sec = Sections[Name];
416+
if (!Sec) {
417+
Sec = make<OutputSection>(Name);
418+
OutputSections.push_back(Sec);
419+
}
407420
Sec->addPermissions(Perms);
408-
OutputSections.push_back(Sec);
409-
Sections[Name] = Sec;
410421
return Sec;
411422
};
412423

@@ -415,7 +426,7 @@ void Writer::createSections() {
415426
CreateSection(".bss", BSS | R | W);
416427
RdataSec = CreateSection(".rdata", DATA | R);
417428
DataSec = CreateSection(".data", DATA | R | W);
418-
PdataSec = CreateSection(".pdata", DATA | R);
429+
CreateSection(".pdata", DATA | R);
419430
IdataSec = CreateSection(".idata", DATA | R);
420431
EdataSec = CreateSection(".edata", DATA | R);
421432
DidatSec = CreateSection(".didat", DATA | R);
@@ -444,12 +455,13 @@ void Writer::createSections() {
444455
// discarded when determining output section. So, .text$foo
445456
// contributes to .text, for example. See PE/COFF spec 3.2.
446457
for (auto Pair : Map) {
447-
StringRef Name = getOutputSection(Pair.first);
448-
OutputSection *&Sec = Sections[Name];
449-
if (!Sec) {
450-
Sec = make<OutputSection>(Name);
451-
OutputSections.push_back(Sec);
458+
StringRef Name = getOutputSectionName(Pair.first);
459+
if (Name == ".pdata") {
460+
if (!FirstPdata)
461+
FirstPdata = Pair.second.front();
462+
LastPdata = Pair.second.back();
452463
}
464+
OutputSection *Sec = CreateSection(Name, 0);
453465
std::vector<Chunk *> &Chunks = Pair.second;
454466
for (Chunk *C : Chunks) {
455467
Sec->addChunk(C);
@@ -838,9 +850,9 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
838850
// Write data directory
839851
auto *Dir = reinterpret_cast<data_directory *>(Buf);
840852
Buf += sizeof(*Dir) * NumberfOfDataDirectory;
841-
if (EdataSec->getVirtualSize()) {
842-
Dir[EXPORT_TABLE].RelativeVirtualAddress = EdataSec->getRVA();
843-
Dir[EXPORT_TABLE].Size = EdataSec->getVirtualSize();
853+
if (!Config->Exports.empty()) {
854+
Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
855+
Dir[EXPORT_TABLE].Size = Edata.getSize();
844856
}
845857
if (!Idata.empty()) {
846858
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
@@ -852,9 +864,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
852864
Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
853865
Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
854866
}
855-
if (PdataSec->getVirtualSize()) {
856-
Dir[EXCEPTION_TABLE].RelativeVirtualAddress = PdataSec->getRVA();
857-
Dir[EXCEPTION_TABLE].Size = PdataSec->getVirtualSize();
867+
if (FirstPdata) {
868+
Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
869+
Dir[EXCEPTION_TABLE].Size =
870+
LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
858871
}
859872
if (RelocSec->getVirtualSize()) {
860873
Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
@@ -1159,11 +1172,15 @@ void Writer::writeBuildId() {
11591172

11601173
// Sort .pdata section contents according to PE/COFF spec 5.5.
11611174
void Writer::sortExceptionTable() {
1162-
if (PdataSec->getVirtualSize() == 0)
1175+
if (!FirstPdata)
11631176
return;
11641177
// We assume .pdata contains function table entries only.
1165-
uint8_t *Begin = Buffer->getBufferStart() + PdataSec->getFileOff();
1166-
uint8_t *End = Begin + PdataSec->getVirtualSize();
1178+
auto BufAddr = [&](Chunk *C) {
1179+
return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
1180+
C->getRVA() - C->getOutputSection()->getRVA();
1181+
};
1182+
uint8_t *Begin = BufAddr(FirstPdata);
1183+
uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
11671184
if (Config->Machine == AMD64) {
11681185
struct Entry { ulittle32_t Begin, End, Unwind; };
11691186
sort(parallel::par, (Entry *)Begin, (Entry *)End,

‎lld/test/COFF/export32.test

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#
33
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
44
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
5+
#
6+
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata
7+
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
8+
# RUN: llvm-readobj -file-headers -sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s
59

610
# CHECK1: Export Table:
711
# CHECK1: DLL name: export32.test.tmp.dll
@@ -10,6 +14,12 @@
1014
# CHECK1-NEXT: 1 0x1008 exportfn1
1115
# CHECK1-NEXT: 2 0x1010 exportfn2
1216

17+
# HEADER-MERGE: ExportTableRVA: 0x2000
18+
# HEADER-MERGE-NEXT: ExportTableSize: 0x7E
19+
# HEADER-MERGE: Name: .rdata
20+
# HEADER-MERGE-NEXT: VirtualSize: 0x7E
21+
# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
22+
1323
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
1424
# RUN: /export:exportfn2 /export:mangled
1525
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s

‎lld/test/COFF/merge.test

+12
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,21 @@
33
# RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
44
# RUN: llvm-readobj -sections %t.exe | FileCheck %s
55

6+
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
7+
# RUN: /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
8+
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
9+
# RUN: /merge:.foo=.rsrc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
10+
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
11+
# RUN: /merge:.reloc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
12+
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
13+
# RUN: /merge:.foo=.reloc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
14+
615
# CHECK: Name: .def
716
# CHECK: Name: .abc
817

18+
# NO-RSRC: /merge: cannot merge '.rsrc' with any section
19+
# NO-RELOC: /merge: cannot merge '.reloc' with any section
20+
921
--- !COFF
1022
header:
1123
Machine: IMAGE_FILE_MACHINE_AMD64

‎lld/test/COFF/unwind.test

+21-5
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,24 @@
44
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
55
# RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s
66
#
7-
# HEADER: ExceptionTableRVA: 0x2000
7+
# RUN: lld-link /merge:.pdata=.rdata /out:%t.exe /entry:main %t.obj
8+
# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s
9+
#
10+
# HEADER: ExceptionTableRVA: 0x3000
11+
#
12+
# FIXME: llvm-readobj currently does not understand files with .pdata merged
13+
# into .rdata. But we can at least check that the section headers look correct.
14+
#
15+
# HEADER-MERGE: ExceptionTableRVA: 0x2000
16+
# HEADER-MERGE-NEXT: ExceptionTableSize: 0x30
17+
# HEADER-MERGE: Name: .rdata
18+
# HEADER-MERGE-NEXT: VirtualSize: 0x34
19+
# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
820
#
921
# UNWIND: Function Table:
1022
# UNWIND: Start Address: 0x1000
1123
# UNWIND: End Address: 0x101b
12-
# UNWIND: Unwind Info Address: 0x3000
24+
# UNWIND: Unwind Info Address: 0x4000
1325
# UNWIND: Version: 1
1426
# UNWIND: Flags: 1 UNW_ExceptionHandler
1527
# UNWIND: Size of prolog: 18
@@ -26,7 +38,7 @@
2638
# UNWIND: Function Table:
2739
# UNWIND: Start Address: 0x1012
2840
# UNWIND: End Address: 0x1012
29-
# UNWIND: Unwind Info Address: 0x301c
41+
# UNWIND: Unwind Info Address: 0x401c
3042
# UNWIND: Version: 1
3143
# UNWIND: Flags: 4 UNW_ChainInfo
3244
# UNWIND: Size of prolog: 0
@@ -35,7 +47,7 @@
3547
# UNWIND: Function Table:
3648
# UNWIND: Start Address: 0x101b
3749
# UNWIND: End Address: 0x101c
38-
# UNWIND: Unwind Info Address: 0x302c
50+
# UNWIND: Unwind Info Address: 0x402c
3951
# UNWIND: Version: 1
4052
# UNWIND: Flags: 0
4153
# UNWIND: Size of prolog: 0
@@ -44,7 +56,7 @@
4456
# UNWIND: Function Table:
4557
# UNWIND: Start Address: 0x101c
4658
# UNWIND: End Address: 0x1039
47-
# UNWIND: Unwind Info Address: 0x3034
59+
# UNWIND: Unwind Info Address: 0x4034
4860
# UNWIND: Version: 1
4961
# UNWIND: Flags: 0
5062
# UNWIND: Size of prolog: 14
@@ -122,6 +134,10 @@ sections:
122134
- VirtualAddress: 44
123135
SymbolName: .xdata
124136
Type: IMAGE_REL_AMD64_ADDR32NB
137+
- Name: .rdata
138+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
139+
Alignment: 4
140+
SectionData: 00000000
125141
symbols:
126142
- Name: .text
127143
Value: 0

0 commit comments

Comments
 (0)
Please sign in to comment.