[lld] r329471 - COFF: Process /merge flag as we create output sections.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 6 17:46:55 PDT 2018


Author: pcc
Date: Fri Apr  6 17:46:55 2018
New Revision: 329471

URL: http://llvm.org/viewvc/llvm-project?rev=329471&view=rev
Log:
COFF: Process /merge flag as we create output sections.

With this we can merge builtin sections.

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

Modified:
    lld/trunk/COFF/DLL.h
    lld/trunk/COFF/DriverUtils.cpp
    lld/trunk/COFF/Writer.cpp
    lld/trunk/test/COFF/export32.test
    lld/trunk/test/COFF/merge.test
    lld/trunk/test/COFF/unwind.test

Modified: lld/trunk/COFF/DLL.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DLL.h?rev=329471&r1=329470&r2=329471&view=diff
==============================================================================
--- lld/trunk/COFF/DLL.h (original)
+++ lld/trunk/COFF/DLL.h Fri Apr  6 17:46:55 2018
@@ -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

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=329471&r1=329470&r2=329471&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Fri Apr  6 17:46:55 2018
@@ -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) {

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=329471&r1=329470&r2=329471&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Fri Apr  6 17:46:55 2018
@@ -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 Writ
   // 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 Writ
     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,

Modified: lld/trunk/test/COFF/export32.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/export32.test?rev=329471&r1=329470&r2=329471&view=diff
==============================================================================
--- lld/trunk/test/COFF/export32.test (original)
+++ lld/trunk/test/COFF/export32.test Fri Apr  6 17:46:55 2018
@@ -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, at 5 \
 # RUN:   /export:exportfn2 /export:mangled
 # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s

Modified: lld/trunk/test/COFF/merge.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/merge.test?rev=329471&r1=329470&r2=329471&view=diff
==============================================================================
--- lld/trunk/test/COFF/merge.test (original)
+++ lld/trunk/test/COFF/merge.test Fri Apr  6 17:46:55 2018
@@ -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

Modified: lld/trunk/test/COFF/unwind.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/unwind.test?rev=329471&r1=329470&r2=329471&view=diff
==============================================================================
--- lld/trunk/test/COFF/unwind.test (original)
+++ lld/trunk/test/COFF/unwind.test Fri Apr  6 17:46:55 2018
@@ -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




More information about the llvm-commits mailing list