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
This commit is contained in:
parent
54fe208a5f
commit
4902508934
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -209,12 +209,23 @@ private:
|
|||
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
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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();
|
||||
|
|
@ -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();
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue