Skip to content

Commit

Permalink
COFF: Process /merge flag as we create output sections.
Browse files Browse the repository at this point in the history
With this we can merge builtin sections.

Differential Revision: https://reviews.llvm.org/D45350

llvm-svn: 329471
  • Loading branch information
pcc committed Apr 7, 2018
1 parent 54fe208 commit 4902508
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 31 deletions.
5 changes: 5 additions & 0 deletions lld/COFF/DLL.h
Expand Up @@ -76,6 +76,11 @@ class EdataContents {
public:
EdataContents();
std::vector<Chunk *> Chunks;

uint64_t getRVA() { return Chunks[0]->getRVA(); }
uint64_t getSize() {
return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
}
};

} // namespace coff
Expand Down
4 changes: 4 additions & 0 deletions lld/COFF/DriverUtils.cpp
Expand Up @@ -185,6 +185,10 @@ void parseMerge(StringRef S) {
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
fatal("/merge: invalid argument: " + S);
if (From == ".rsrc" || To == ".rsrc")
fatal("/merge: cannot merge '.rsrc' with any section");
if (From == ".reloc" || To == ".reloc")
fatal("/merge: cannot merge '.reloc' with any section");
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
Expand Down
69 changes: 43 additions & 26 deletions lld/COFF/Writer.cpp
Expand Up @@ -209,12 +209,23 @@ class Writer {
OutputSection *TextSec;
OutputSection *RdataSec;
OutputSection *DataSec;
OutputSection *PdataSec;
OutputSection *IdataSec;
OutputSection *EdataSec;
OutputSection *DidatSec;
OutputSection *RsrcSec;
OutputSection *RelocSec;

// The first and last .pdata sections in the output file.
//
// We need to keep track of the location of .pdata in whichever section it
// gets merged into so that we can sort its contents and emit a correct data
// directory entry for the exception table. This is also the case for some
// other sections (such as .edata) but because the contents of those sections
// are entirely linker-generated we can keep track of their locations using
// the chunks that the linker creates. All .pdata chunks come from input
// files, so we need to keep track of them separately.
Chunk *FirstPdata = nullptr;
Chunk *LastPdata;
};
} // anonymous namespace

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

static StringRef getOutputSection(StringRef Name) {
static StringRef getOutputSectionName(StringRef Name) {
StringRef S = Name.split('$').first;

// Treat a later period as a separator for MinGW, for sections like
// ".ctors.01234".
S = S.substr(0, S.find('.', 1));

auto It = Config->Merge.find(S);
if (It == Config->Merge.end())
return S;
return It->second;
return S.substr(0, S.find('.', 1));
}

// For /order.
Expand Down Expand Up @@ -403,10 +409,15 @@ void Writer::createSections() {

SmallDenseMap<StringRef, OutputSection *> Sections;
auto CreateSection = [&](StringRef Name, uint32_t Perms) {
auto Sec = make<OutputSection>(Name);
auto I = Config->Merge.find(Name);
if (I != Config->Merge.end())
Name = I->second;
OutputSection *&Sec = Sections[Name];
if (!Sec) {
Sec = make<OutputSection>(Name);
OutputSections.push_back(Sec);
}
Sec->addPermissions(Perms);
OutputSections.push_back(Sec);
Sections[Name] = Sec;
return Sec;
};

Expand All @@ -415,7 +426,7 @@ void Writer::createSections() {
CreateSection(".bss", BSS | R | W);
RdataSec = CreateSection(".rdata", DATA | R);
DataSec = CreateSection(".data", DATA | R | W);
PdataSec = CreateSection(".pdata", DATA | R);
CreateSection(".pdata", DATA | R);
IdataSec = CreateSection(".idata", DATA | R);
EdataSec = CreateSection(".edata", DATA | R);
DidatSec = CreateSection(".didat", DATA | R);
Expand Down Expand Up @@ -444,12 +455,13 @@ void Writer::createSections() {
// discarded when determining output section. So, .text$foo
// contributes to .text, for example. See PE/COFF spec 3.2.
for (auto Pair : Map) {
StringRef Name = getOutputSection(Pair.first);
OutputSection *&Sec = Sections[Name];
if (!Sec) {
Sec = make<OutputSection>(Name);
OutputSections.push_back(Sec);
StringRef Name = getOutputSectionName(Pair.first);
if (Name == ".pdata") {
if (!FirstPdata)
FirstPdata = Pair.second.front();
LastPdata = Pair.second.back();
}
OutputSection *Sec = CreateSection(Name, 0);
std::vector<Chunk *> &Chunks = Pair.second;
for (Chunk *C : Chunks) {
Sec->addChunk(C);
Expand Down Expand Up @@ -838,9 +850,9 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
// Write data directory
auto *Dir = reinterpret_cast<data_directory *>(Buf);
Buf += sizeof(*Dir) * NumberfOfDataDirectory;
if (EdataSec->getVirtualSize()) {
Dir[EXPORT_TABLE].RelativeVirtualAddress = EdataSec->getRVA();
Dir[EXPORT_TABLE].Size = EdataSec->getVirtualSize();
if (!Config->Exports.empty()) {
Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
Dir[EXPORT_TABLE].Size = Edata.getSize();
}
if (!Idata.empty()) {
Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
Expand All @@ -852,9 +864,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
}
if (PdataSec->getVirtualSize()) {
Dir[EXCEPTION_TABLE].RelativeVirtualAddress = PdataSec->getRVA();
Dir[EXCEPTION_TABLE].Size = PdataSec->getVirtualSize();
if (FirstPdata) {
Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
Dir[EXCEPTION_TABLE].Size =
LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
}
if (RelocSec->getVirtualSize()) {
Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
Expand Down Expand Up @@ -1159,11 +1172,15 @@ void Writer::writeBuildId() {

// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
if (PdataSec->getVirtualSize() == 0)
if (!FirstPdata)
return;
// We assume .pdata contains function table entries only.
uint8_t *Begin = Buffer->getBufferStart() + PdataSec->getFileOff();
uint8_t *End = Begin + PdataSec->getVirtualSize();
auto BufAddr = [&](Chunk *C) {
return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
C->getRVA() - C->getOutputSection()->getRVA();
};
uint8_t *Begin = BufAddr(FirstPdata);
uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
sort(parallel::par, (Entry *)Begin, (Entry *)End,
Expand Down
10 changes: 10 additions & 0 deletions lld/test/COFF/export32.test
Expand Up @@ -2,6 +2,10 @@
#
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
#
# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s
# RUN: llvm-readobj -file-headers -sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s

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

# HEADER-MERGE: ExportTableRVA: 0x2000
# HEADER-MERGE-NEXT: ExportTableSize: 0x7E
# HEADER-MERGE: Name: .rdata
# HEADER-MERGE-NEXT: VirtualSize: 0x7E
# HEADER-MERGE-NEXT: VirtualAddress: 0x2000

# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \
# RUN: /export:exportfn2 /export:mangled
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s
Expand Down
12 changes: 12 additions & 0 deletions lld/test/COFF/merge.test
Expand Up @@ -3,9 +3,21 @@
# RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug
# RUN: llvm-readobj -sections %t.exe | FileCheck %s

# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
# RUN: /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
# RUN: /merge:.foo=.rsrc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
# RUN: /merge:.reloc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s
# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \
# RUN: /merge:.foo=.reloc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s

# CHECK: Name: .def
# CHECK: Name: .abc

# NO-RSRC: /merge: cannot merge '.rsrc' with any section
# NO-RELOC: /merge: cannot merge '.reloc' with any section

--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_AMD64
Expand Down
26 changes: 21 additions & 5 deletions lld/test/COFF/unwind.test
Expand Up @@ -4,12 +4,24 @@
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
# RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s
#
# HEADER: ExceptionTableRVA: 0x2000
# RUN: lld-link /merge:.pdata=.rdata /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s
#
# HEADER: ExceptionTableRVA: 0x3000
#
# FIXME: llvm-readobj currently does not understand files with .pdata merged
# into .rdata. But we can at least check that the section headers look correct.
#
# HEADER-MERGE: ExceptionTableRVA: 0x2000
# HEADER-MERGE-NEXT: ExceptionTableSize: 0x30
# HEADER-MERGE: Name: .rdata
# HEADER-MERGE-NEXT: VirtualSize: 0x34
# HEADER-MERGE-NEXT: VirtualAddress: 0x2000
#
# UNWIND: Function Table:
# UNWIND: Start Address: 0x1000
# UNWIND: End Address: 0x101b
# UNWIND: Unwind Info Address: 0x3000
# UNWIND: Unwind Info Address: 0x4000
# UNWIND: Version: 1
# UNWIND: Flags: 1 UNW_ExceptionHandler
# UNWIND: Size of prolog: 18
Expand All @@ -26,7 +38,7 @@
# UNWIND: Function Table:
# UNWIND: Start Address: 0x1012
# UNWIND: End Address: 0x1012
# UNWIND: Unwind Info Address: 0x301c
# UNWIND: Unwind Info Address: 0x401c
# UNWIND: Version: 1
# UNWIND: Flags: 4 UNW_ChainInfo
# UNWIND: Size of prolog: 0
Expand All @@ -35,7 +47,7 @@
# UNWIND: Function Table:
# UNWIND: Start Address: 0x101b
# UNWIND: End Address: 0x101c
# UNWIND: Unwind Info Address: 0x302c
# UNWIND: Unwind Info Address: 0x402c
# UNWIND: Version: 1
# UNWIND: Flags: 0
# UNWIND: Size of prolog: 0
Expand All @@ -44,7 +56,7 @@
# UNWIND: Function Table:
# UNWIND: Start Address: 0x101c
# UNWIND: End Address: 0x1039
# UNWIND: Unwind Info Address: 0x3034
# UNWIND: Unwind Info Address: 0x4034
# UNWIND: Version: 1
# UNWIND: Flags: 0
# UNWIND: Size of prolog: 14
Expand Down Expand Up @@ -122,6 +134,10 @@ sections:
- VirtualAddress: 44
SymbolName: .xdata
Type: IMAGE_REL_AMD64_ADDR32NB
- Name: .rdata
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
Alignment: 4
SectionData: 00000000
symbols:
- Name: .text
Value: 0
Expand Down

0 comments on commit 4902508

Please sign in to comment.