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
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.
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;
};
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);
// 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);
// 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();
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();
// 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,
# 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
# 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
# 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
# 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
- 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