[lld] r329370 - COFF: Create output sections early. NFCI.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 5 20:25:49 PDT 2018


Author: pcc
Date: Thu Apr  5 20:25:49 2018
New Revision: 329370

URL: http://llvm.org/viewvc/llvm-project?rev=329370&view=rev
Log:
COFF: Create output sections early. NFCI.

With this, all output sections are created in one place. This will make
it simpler to implement merging of builtin sections.

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

Modified:
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=329370&r1=329369&r2=329370&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Thu Apr  5 20:25:49 2018
@@ -163,14 +163,13 @@ private:
   void createSymbolAndStringTable();
   void openFile(StringRef OutputPath);
   template <typename PEHeaderTy> void writeHeader();
-  void createSEHTable(OutputSection *RData);
-  void createGuardCFTables(OutputSection *RData);
-  void createGLJmpTable(OutputSection *RData);
+  void createSEHTable();
+  void createGuardCFTables();
   void markSymbolsForRVATable(ObjFile *File,
                               ArrayRef<SectionChunk *> SymIdxChunks,
                               SymbolRVASet &TableSymbols);
-  void maybeAddRVATable(OutputSection *RData, SymbolRVASet TableSymbols,
-                        StringRef TableSym, StringRef CountSym);
+  void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+                        StringRef CountSym);
   void setSectionPermissions();
   void writeSections();
   void writeBuildId();
@@ -180,9 +179,8 @@ private:
   size_t addEntryToStringTable(StringRef Str);
 
   OutputSection *findSection(StringRef Name);
-  OutputSection *createSection(StringRef Name);
-  void addBaserels(OutputSection *Dest);
-  void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
+  void addBaserels();
+  void addBaserelBlocks(std::vector<Baserel> &V);
 
   uint32_t getSizeOfInitializedData();
   std::map<StringRef, std::vector<DefinedImportData *>> binImports();
@@ -207,6 +205,16 @@ private:
   uint32_t PointerToSymbolTable = 0;
   uint64_t SizeOfImage;
   uint64_t SizeOfHeaders;
+
+  OutputSection *TextSec;
+  OutputSection *RdataSec;
+  OutputSection *DataSec;
+  OutputSection *PdataSec;
+  OutputSection *IdataSec;
+  OutputSection *EdataSec;
+  OutputSection *DidatSec;
+  OutputSection *RsrcSec;
+  OutputSection *RelocSec;
 };
 } // anonymous namespace
 
@@ -318,8 +326,6 @@ void Writer::run() {
   createMiscChunks();
   createImportTables();
   createExportTable();
-  if (Config->Relocatable)
-    createSection(".reloc");
   assignAddresses();
   removeEmptySections();
   setSectionPermissions();
@@ -386,7 +392,37 @@ static void sortBySectionOrder(std::vect
 
 // Create output section objects and add them to OutputSections.
 void Writer::createSections() {
-  // First, bin chunks by name.
+  // First, create the builtin sections.
+  const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+  const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+  const uint32_t CODE = IMAGE_SCN_CNT_CODE;
+  const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+  const uint32_t R = IMAGE_SCN_MEM_READ;
+  const uint32_t W = IMAGE_SCN_MEM_WRITE;
+  const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
+
+  SmallDenseMap<StringRef, OutputSection *> Sections;
+  auto CreateSection = [&](StringRef Name, uint32_t Perms) {
+    auto Sec = make<OutputSection>(Name);
+    Sec->addPermissions(Perms);
+    OutputSections.push_back(Sec);
+    Sections[Name] = Sec;
+    return Sec;
+  };
+
+  // Try to match the section order used by link.exe.
+  TextSec = CreateSection(".text", CODE | R | X);
+  CreateSection(".bss", BSS | R | W);
+  RdataSec = CreateSection(".rdata", DATA | R);
+  DataSec = CreateSection(".data", DATA | R | W);
+  PdataSec = CreateSection(".pdata", DATA | R);
+  IdataSec = CreateSection(".idata", DATA | R);
+  EdataSec = CreateSection(".edata", DATA | R);
+  DidatSec = CreateSection(".didat", DATA | R);
+  RsrcSec = CreateSection(".rsrc", DATA | R);
+  RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
+
+  // Then bin chunks by name.
   std::map<StringRef, std::vector<Chunk *>> Map;
   for (Chunk *C : Symtab->getChunks()) {
     auto *SC = dyn_cast<SectionChunk>(C);
@@ -407,7 +443,6 @@ void Writer::createSections() {
   // '$' and all following characters in input section names are
   // discarded when determining output section. So, .text$foo
   // contributes to .text, for example. See PE/COFF spec 3.2.
-  SmallDenseMap<StringRef, OutputSection *> Sections;
   for (auto Pair : Map) {
     StringRef Name = getOutputSection(Pair.first);
     OutputSection *&Sec = Sections[Name];
@@ -421,18 +456,38 @@ void Writer::createSections() {
       Sec->addPermissions(C->getPermissions());
     }
   }
+
+  // Finally, move some output sections to the end.
+  auto SectionOrder = [&](OutputSection *S) {
+    // .reloc should come last of all since it refers to RVAs of data in the
+    // previous sections.
+    if (S == RelocSec)
+      return 3;
+    // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+    // the loader cannot handle holes.
+    if (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE)
+      return 2;
+    // .rsrc should come at the end of the non-discardable sections because its
+    // size may change by the Win32 UpdateResources() function, causing
+    // subsequent sections to move (see https://crbug.com/827082).
+    if (S == RsrcSec)
+      return 1;
+    return 0;
+  };
+  std::stable_sort(OutputSections.begin(), OutputSections.end(),
+                   [&](OutputSection *S, OutputSection *T) {
+                     return SectionOrder(S) < SectionOrder(T);
+                   });
 }
 
 void Writer::createMiscChunks() {
-  OutputSection *RData = createSection(".rdata");
-
   for (auto &P : MergeChunk::Instances)
-    RData->addChunk(P.second);
+    RdataSec->addChunk(P.second);
 
   // Create thunks for locally-dllimported symbols.
   if (!Symtab->LocalImportChunks.empty()) {
     for (Chunk *C : Symtab->LocalImportChunks)
-      RData->addChunk(C);
+      RdataSec->addChunk(C);
   }
 
   // Create Debug Information Chunks
@@ -447,18 +502,18 @@ void Writer::createMiscChunks() {
     BuildId = CVChunk;
     DebugRecords.push_back(CVChunk);
 
-    RData->addChunk(DebugDirectory);
+    RdataSec->addChunk(DebugDirectory);
     for (Chunk *C : DebugRecords)
-      RData->addChunk(C);
+      RdataSec->addChunk(C);
   }
 
   // Create SEH table. x86-only.
   if (Config->Machine == I386)
-    createSEHTable(RData);
+    createSEHTable();
 
   // Create /guard:cf tables if requested.
   if (Config->GuardCF != GuardCFLevel::Off)
-    createGuardCFTables(RData);
+    createGuardCFTables();
 }
 
 // Create .idata section for the DLL-imported symbol table.
@@ -481,13 +536,12 @@ void Writer::createImportTables() {
       Config->DLLOrder[DLL] = Config->DLLOrder.size();
   }
 
-  OutputSection *Text = createSection(".text");
   for (ImportFile *File : ImportFile::Instances) {
     if (!File->Live)
       continue;
 
     if (DefinedImportThunk *Thunk = File->ThunkSym)
-      Text->addChunk(Thunk->getChunk());
+      TextSec->addChunk(Thunk->getChunk());
 
     if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
       if (!File->ThunkSym)
@@ -499,33 +553,27 @@ void Writer::createImportTables() {
     }
   }
 
-  if (!Idata.empty()) {
-    OutputSection *Sec = createSection(".idata");
+  if (!Idata.empty())
     for (Chunk *C : Idata.getChunks())
-      Sec->addChunk(C);
-  }
+      IdataSec->addChunk(C);
 
   if (!DelayIdata.empty()) {
     Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
     DelayIdata.create(Helper);
-    OutputSection *Sec = createSection(".didat");
     for (Chunk *C : DelayIdata.getChunks())
-      Sec->addChunk(C);
-    Sec = createSection(".data");
+      DidatSec->addChunk(C);
     for (Chunk *C : DelayIdata.getDataChunks())
-      Sec->addChunk(C);
-    Sec = createSection(".text");
+      DataSec->addChunk(C);
     for (Chunk *C : DelayIdata.getCodeChunks())
-      Sec->addChunk(C);
+      TextSec->addChunk(C);
   }
 }
 
 void Writer::createExportTable() {
   if (Config->Exports.empty())
     return;
-  OutputSection *Sec = createSection(".edata");
   for (Chunk *C : Edata.Chunks)
-    Sec->addChunk(C);
+    EdataSec->addChunk(C);
 }
 
 // The Windows loader doesn't seem to like empty sections,
@@ -644,29 +692,6 @@ void Writer::createSymbolAndStringTable(
   FileSize = alignTo(FileOff, SectorSize);
 }
 
-static int sectionIndex(OutputSection *S) {
-  // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
-  // the loader cannot handle holes.
-  if (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE)
-    return 101;
-
-  // Try to match the section order used by link.exe. In particular, it's
-  // important that .reloc comes last since it refers to RVA's of data in
-  // the previous sections. .rsrc should come late because its size may
-  // change by the Win32 UpdateResources() function, causing subsequent
-  // sections to move (see https://crbug.com/827082).
-  return StringSwitch<int>(S->Name)
-      .Case(".text", 1)
-      .Case(".bss", 2)
-      .Case(".rdata", 3)
-      .Case(".data", 4)
-      .Case(".pdata", 5)
-      .Case(".idata", 6)
-      .Case(".rsrc", 99)
-      .Case(".reloc", 100)
-      .Default(50); // Default to somewhere in the middle.
-}
-
 // Visits all sections to assign incremental, non-overlapping RVAs and
 // file offsets.
 void Writer::assignAddresses() {
@@ -679,15 +704,9 @@ void Writer::assignAddresses() {
   uint64_t RVA = PageSize; // The first page is kept unmapped.
   FileSize = SizeOfHeaders;
 
-  // Reorder the sections.
-  std::stable_sort(OutputSections.begin(), OutputSections.end(),
-                   [](OutputSection *S, OutputSection *T) {
-                     return sectionIndex(S) < sectionIndex(T);
-                   });
-
   for (OutputSection *Sec : OutputSections) {
-    if (Sec->Name == ".reloc")
-      addBaserels(Sec);
+    if (Sec == RelocSec)
+      addBaserels();
     uint64_t RawSize = 0, VirtualSize = 0;
     Sec->Header.VirtualAddress = RVA;
     for (Chunk *C : Sec->getChunks()) {
@@ -810,18 +829,18 @@ template <typename PEHeaderTy> void Writ
   if (Config->TerminalServerAware)
     PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
   PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
-  if (OutputSection *Text = findSection(".text")) {
-    PE->BaseOfCode = Text->getRVA();
-    PE->SizeOfCode = Text->getRawSize();
+  if (TextSec->getVirtualSize()) {
+    PE->BaseOfCode = TextSec->getRVA();
+    PE->SizeOfCode = TextSec->getRawSize();
   }
   PE->SizeOfInitializedData = getSizeOfInitializedData();
 
   // Write data directory
   auto *Dir = reinterpret_cast<data_directory *>(Buf);
   Buf += sizeof(*Dir) * NumberfOfDataDirectory;
-  if (OutputSection *Sec = findSection(".edata")) {
-    Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
-    Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+  if (EdataSec->getVirtualSize()) {
+    Dir[EXPORT_TABLE].RelativeVirtualAddress = EdataSec->getRVA();
+    Dir[EXPORT_TABLE].Size = EdataSec->getVirtualSize();
   }
   if (!Idata.empty()) {
     Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
@@ -829,17 +848,17 @@ template <typename PEHeaderTy> void Writ
     Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
     Dir[IAT].Size = Idata.getIATSize();
   }
-  if (OutputSection *Sec = findSection(".rsrc")) {
-    Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
-    Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
-  }
-  if (OutputSection *Sec = findSection(".pdata")) {
-    Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
-    Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
-  }
-  if (OutputSection *Sec = findSection(".reloc")) {
-    Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
-    Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+  if (RsrcSec->getVirtualSize()) {
+    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 (RelocSec->getVirtualSize()) {
+    Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
+    Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
   }
   if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
     if (Defined *B = dyn_cast<Defined>(Sym)) {
@@ -908,7 +927,7 @@ void Writer::openFile(StringRef Path) {
       "failed to open " + Path);
 }
 
-void Writer::createSEHTable(OutputSection *RData) {
+void Writer::createSEHTable() {
   SymbolRVASet Handlers;
   for (ObjFile *File : ObjFile::Instances) {
     // FIXME: We should error here instead of earlier unless /safeseh:no was
@@ -919,7 +938,7 @@ void Writer::createSEHTable(OutputSectio
     markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
   }
 
-  maybeAddRVATable(RData, std::move(Handlers), "__safe_se_handler_table",
+  maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
                    "__safe_se_handler_count");
 }
 
@@ -964,7 +983,7 @@ static void markSymbolsWithRelocations(O
 // Create the guard function id table. This is a table of RVAs of all
 // address-taken functions. It is sorted and uniqued, just like the safe SEH
 // table.
-void Writer::createGuardCFTables(OutputSection *RData) {
+void Writer::createGuardCFTables() {
   SymbolRVASet AddressTakenSyms;
   SymbolRVASet LongJmpTargets;
   for (ObjFile *File : ObjFile::Instances) {
@@ -985,12 +1004,12 @@ void Writer::createGuardCFTables(OutputS
   if (Config->Entry)
     addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
 
-  maybeAddRVATable(RData, std::move(AddressTakenSyms), "__guard_fids_table",
+  maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
                    "__guard_fids_count");
 
   // Add the longjmp target table unless the user told us not to.
   if (Config->GuardCF == GuardCFLevel::Full)
-    maybeAddRVATable(RData, std::move(LongJmpTargets), "__guard_longjmp_table",
+    maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
                      "__guard_longjmp_count");
 
   // Set __guard_flags, which will be used in the load config to indicate that
@@ -1047,14 +1066,13 @@ void Writer::markSymbolsForRVATable(ObjF
 // Replace the absolute table symbol with a synthetic symbol pointing to
 // TableChunk so that we can emit base relocations for it and resolve section
 // relative relocations.
-void Writer::maybeAddRVATable(OutputSection *RData,
-                              SymbolRVASet TableSymbols,
-                              StringRef TableSym, StringRef CountSym) {
+void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+                              StringRef CountSym) {
   if (TableSymbols.empty())
     return;
 
   RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
-  RData->addChunk(TableChunk);
+  RdataSec->addChunk(TableChunk);
 
   Symbol *T = Symtab->findUnderscore(TableSym);
   Symbol *C = Symtab->findUnderscore(CountSym);
@@ -1141,12 +1159,11 @@ void Writer::writeBuildId() {
 
 // Sort .pdata section contents according to PE/COFF spec 5.5.
 void Writer::sortExceptionTable() {
-  OutputSection *Sec = findSection(".pdata");
-  if (!Sec)
+  if (PdataSec->getVirtualSize() == 0)
     return;
   // We assume .pdata contains function table entries only.
-  uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
-  uint8_t *End = Begin + Sec->getVirtualSize();
+  uint8_t *Begin = Buffer->getBufferStart() + PdataSec->getFileOff();
+  uint8_t *End = Begin + PdataSec->getVirtualSize();
   if (Config->Machine == AMD64) {
     struct Entry { ulittle32_t Begin, End, Unwind; };
     sort(parallel::par, (Entry *)Begin, (Entry *)End,
@@ -1177,50 +1194,26 @@ uint32_t Writer::getSizeOfInitializedDat
   return Res;
 }
 
-// Returns an existing section or create a new one if not found.
-OutputSection *Writer::createSection(StringRef Name) {
-  if (auto *Sec = findSection(Name))
-    return Sec;
-  const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
-  const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
-  const auto CODE = IMAGE_SCN_CNT_CODE;
-  const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
-  const auto R = IMAGE_SCN_MEM_READ;
-  const auto W = IMAGE_SCN_MEM_WRITE;
-  const auto X = IMAGE_SCN_MEM_EXECUTE;
-  uint32_t Perms = StringSwitch<uint32_t>(Name)
-                       .Case(".bss", BSS | R | W)
-                       .Case(".data", DATA | R | W)
-                       .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R)
-                       .Case(".reloc", DATA | DISCARDABLE | R)
-                       .Case(".text", CODE | R | X)
-                       .Default(0);
-  if (!Perms)
-    llvm_unreachable("unknown section name");
-  auto Sec = make<OutputSection>(Name);
-  Sec->addPermissions(Perms);
-  OutputSections.push_back(Sec);
-  return Sec;
-}
-
-// Dest is .reloc section. Add contents to that section.
-void Writer::addBaserels(OutputSection *Dest) {
+// Add base relocations to .reloc section.
+void Writer::addBaserels() {
+  if (!Config->Relocatable)
+    return;
   std::vector<Baserel> V;
   for (OutputSection *Sec : OutputSections) {
-    if (Sec == Dest)
+    if (Sec == RelocSec)
       continue;
     // Collect all locations for base relocations.
     for (Chunk *C : Sec->getChunks())
       C->getBaserels(&V);
     // Add the addresses to .reloc section.
     if (!V.empty())
-      addBaserelBlocks(Dest, V);
+      addBaserelBlocks(V);
     V.clear();
   }
 }
 
 // Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
   const uint32_t Mask = ~uint32_t(PageSize - 1);
   uint32_t Page = V[0].RVA & Mask;
   size_t I = 0, J = 1;
@@ -1228,11 +1221,11 @@ void Writer::addBaserelBlocks(OutputSect
     uint32_t P = V[J].RVA & Mask;
     if (P == Page)
       continue;
-    Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+    RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
     I = J;
     Page = P;
   }
   if (I == J)
     return;
-  Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+  RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
 }




More information about the llvm-commits mailing list