[lld] r372734 - [ELF] Make MergeInputSection merging aware of output sections

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 24 04:48:31 PDT 2019


Author: maskray
Date: Tue Sep 24 04:48:31 2019
New Revision: 372734

URL: http://llvm.org/viewvc/llvm-project?rev=372734&view=rev
Log:
[ELF] Make MergeInputSection merging aware of output sections

Fixes PR38748

mergeSections() calls getOutputSectionName() to get output section
names. Two MergeInputSections may be merged even if they are made
different by SECTIONS commands.

This patch moves mergeSections() after processSectionCommands() and
addOrphanSections() to fix the issue. The new pass is renamed to
OutputSection::finalizeInputSections().

processSectionCommands() and addorphanSections() are changed to add
sections to InputSectionDescription::sectionBases.

finalizeInputSections() merges MergeInputSections and migrates
`sectionBases` to `sections`.

For the -r case, we drop an optimization that tries keeping sh_entsize
non-zero. This is for the simplicity of addOrphanSections(). The
updated merge-entsize2.s reflects the change.

Reviewed By: grimar

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

Added:
    lld/trunk/test/ELF/linkerscript/merge-output-sections.s
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/SyntheticSections.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/linkerscript/merge-sections.s
    lld/trunk/test/ELF/merge-entsize2.s

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Tue Sep 24 04:48:31 2019
@@ -1889,8 +1889,7 @@ template <class ELFT> void LinkerDriver:
            "feature detected");
   }
 
-  // This adds a .comment section containing a version string. We have to add it
-  // before mergeSections because the .comment section is a mergeable section.
+  // This adds a .comment section containing a version string.
   if (!config->relocatable)
     inputSections.push_back(createCommentSection());
 
@@ -1902,7 +1901,6 @@ template <class ELFT> void LinkerDriver:
   splitSections<ELFT>();
   markLive<ELFT>();
   demoteSharedSymbols();
-  mergeSections();
 
   // Make copies of any input sections that need to be copied into each
   // partition.
@@ -1926,6 +1924,16 @@ template <class ELFT> void LinkerDriver:
   // they are assigned to output sections by the default rule. Process that.
   script->addOrphanSections();
 
+  // Migrate InputSectionDescription::sectionBases to sections. This includes
+  // merging MergeInputSections into a single MergeSyntheticSection. From this
+  // point onwards InputSectionDescription::sections should be used instead of
+  // sectionBases.
+  for (BaseCommand *base : script->sectionCommands)
+    if (auto *sec = dyn_cast<OutputSection>(base))
+      sec->finalizeInputSections();
+  llvm::erase_if(inputSections,
+                 [](InputSectionBase *s) { return isa<MergeInputSection>(s); });
+
   // Two input sections with different output sections should not be folded.
   // ICF runs after processSectionCommands() so that we know the output sections.
   if (config->icf != ICFLevel::None) {

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Tue Sep 24 04:48:31 2019
@@ -341,19 +341,19 @@ bool LinkerScript::shouldKeep(InputSecti
 }
 
 // A helper function for the SORT() command.
-static bool matchConstraints(ArrayRef<InputSection *> sections,
+static bool matchConstraints(ArrayRef<InputSectionBase *> sections,
                              ConstraintKind kind) {
   if (kind == ConstraintKind::NoConstraint)
     return true;
 
   bool isRW = llvm::any_of(
-      sections, [](InputSection *sec) { return sec->flags & SHF_WRITE; });
+      sections, [](InputSectionBase *sec) { return sec->flags & SHF_WRITE; });
 
   return (isRW && kind == ConstraintKind::ReadWrite) ||
          (!isRW && kind == ConstraintKind::ReadOnly);
 }
 
-static void sortSections(MutableArrayRef<InputSection *> vec,
+static void sortSections(MutableArrayRef<InputSectionBase *> vec,
                          SortSectionPolicy k) {
   auto alignmentComparator = [](InputSectionBase *a, InputSectionBase *b) {
     // ">" is not a mistake. Sections with larger alignments are placed
@@ -392,7 +392,7 @@ static void sortSections(MutableArrayRef
 //    --sort-section is handled as an inner SORT command.
 // 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
 // 4. If no SORT command is given, sort according to --sort-section.
-static void sortInputSections(MutableArrayRef<InputSection *> vec,
+static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
                               const SectionPattern &pat) {
   if (pat.sortOuter == SortSectionPolicy::None)
     return;
@@ -405,9 +405,9 @@ static void sortInputSections(MutableArr
 }
 
 // Compute and remember which sections the InputSectionDescription matches.
-std::vector<InputSection *>
+std::vector<InputSectionBase *>
 LinkerScript::computeInputSections(const InputSectionDescription *cmd) {
-  std::vector<InputSection *> ret;
+  std::vector<InputSectionBase *> ret;
 
   // Collects all sections that satisfy constraints of Cmd.
   for (const SectionPattern &pat : cmd->sectionPatterns) {
@@ -422,10 +422,8 @@ LinkerScript::computeInputSections(const
       // which are common because they are in the default bfd script.
       // We do not ignore SHT_REL[A] linker-synthesized sections here because
       // want to support scripts that do custom layout for them.
-      //
-      // It is safe to assume that Sec is an InputSection because mergeable or
-      // EH input sections have already been handled and eliminated.
-      if (cast<InputSection>(sec)->getRelocatedSection())
+      if (isa<InputSection>(sec) &&
+          cast<InputSection>(sec)->getRelocatedSection())
         continue;
 
       std::string filename = getFilename(sec->file);
@@ -434,42 +432,41 @@ LinkerScript::computeInputSections(const
           !pat.sectionPat.match(sec->name))
         continue;
 
-      ret.push_back(cast<InputSection>(sec));
+      ret.push_back(sec);
       sec->assigned = true;
     }
 
-    sortInputSections(MutableArrayRef<InputSection *>(ret).slice(sizeBefore),
-                      pat);
+    sortInputSections(
+        MutableArrayRef<InputSectionBase *>(ret).slice(sizeBefore), pat);
   }
   return ret;
 }
 
-void LinkerScript::discard(ArrayRef<InputSection *> v) {
-  for (InputSection *s : v) {
-    if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn)
-      error("discarding " + s->name + " section is not allowed");
-
-    // You can discard .hash and .gnu.hash sections by linker scripts. Since
-    // they are synthesized sections, we need to handle them differently than
-    // other regular sections.
-    if (s == mainPart->gnuHashTab)
-      mainPart->gnuHashTab = nullptr;
-    if (s == mainPart->hashTab)
-      mainPart->hashTab = nullptr;
-
-    s->markDead();
-    discard(s->dependentSections);
-  }
+void LinkerScript::discard(InputSectionBase *s) {
+  if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn)
+    error("discarding " + s->name + " section is not allowed");
+
+  // You can discard .hash and .gnu.hash sections by linker scripts. Since
+  // they are synthesized sections, we need to handle them differently than
+  // other regular sections.
+  if (s == mainPart->gnuHashTab)
+    mainPart->gnuHashTab = nullptr;
+  if (s == mainPart->hashTab)
+    mainPart->hashTab = nullptr;
+
+  s->markDead();
+  for (InputSection *ds : s->dependentSections)
+    discard(ds);
 }
 
-std::vector<InputSection *>
+std::vector<InputSectionBase *>
 LinkerScript::createInputSectionList(OutputSection &outCmd) {
-  std::vector<InputSection *> ret;
+  std::vector<InputSectionBase *> ret;
 
   for (BaseCommand *base : outCmd.sectionCommands) {
     if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
-      cmd->sections = computeInputSections(cmd);
-      ret.insert(ret.end(), cmd->sections.begin(), cmd->sections.end());
+      cmd->sectionBases = computeInputSections(cmd);
+      ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end());
     }
   }
   return ret;
@@ -480,12 +477,13 @@ void LinkerScript::processSectionCommand
   size_t i = 0;
   for (BaseCommand *base : sectionCommands) {
     if (auto *sec = dyn_cast<OutputSection>(base)) {
-      std::vector<InputSection *> v = createInputSectionList(*sec);
+      std::vector<InputSectionBase *> v = createInputSectionList(*sec);
 
       // The output section name `/DISCARD/' is special.
       // Any input section assigned to it is discarded.
       if (sec->name == "/DISCARD/") {
-        discard(v);
+        for (InputSectionBase *s : v)
+          discard(s);
         sec->sectionCommands.clear();
         continue;
       }
@@ -513,15 +511,9 @@ void LinkerScript::processSectionCommand
           s->alignment = subalign;
       }
 
-      // Some input sections may be removed from the list after ICF.
-      for (InputSection *s : v)
-        sec->addSection(s);
-
       sec->sectionIndex = i++;
-      if (sec->noload)
-        sec->type = SHT_NOBITS;
-      if (sec->nonAlloc)
-        sec->flags &= ~(uint64_t)SHF_ALLOC;
+      for (InputSectionBase *s : v)
+        s->parent = sec;
     }
   }
 }
@@ -565,7 +557,7 @@ static OutputSection *findByName(ArrayRe
 static OutputSection *createSection(InputSectionBase *isec,
                                     StringRef outsecName) {
   OutputSection *sec = script->createOutputSection(outsecName, "<internal>");
-  sec->addSection(cast<InputSection>(isec));
+  sec->recordSection(isec);
   return sec;
 }
 
@@ -594,7 +586,7 @@ addInputSec(StringMap<TinyPtrVector<Outp
     OutputSection *out = sec->getRelocatedSection()->getOutputSection();
 
     if (out->relocationSection) {
-      out->relocationSection->addSection(sec);
+      out->relocationSection->recordSection(sec);
       return nullptr;
     }
 
@@ -602,12 +594,6 @@ addInputSec(StringMap<TinyPtrVector<Outp
     return out->relocationSection;
   }
 
-  // When control reaches here, mergeable sections have already been merged into
-  // synthetic sections. For relocatable case we want to create one output
-  // section per syntetic section so that they have a valid sh_entsize.
-  if (config->relocatable && (isec->flags & SHF_MERGE))
-    return createSection(isec, outsecName);
-
   //  The ELF spec just says
   // ----------------------------------------------------------------
   // In the first phase, input sections that match in name, type and
@@ -654,7 +640,7 @@ addInputSec(StringMap<TinyPtrVector<Outp
   for (OutputSection *sec : v) {
     if (sec->partition != isec->partition)
       continue;
-    sec->addSection(cast<InputSection>(isec));
+    sec->recordSection(isec);
     return nullptr;
   }
 
@@ -680,13 +666,14 @@ void LinkerScript::addOrphanSections() {
       warn(toString(s) + " is being placed in '" + name + "'");
 
     if (OutputSection *sec = findByName(sectionCommands, name)) {
-      sec->addSection(cast<InputSection>(s));
+      sec->recordSection(s);
       return;
     }
 
     if (OutputSection *os = addInputSec(map, s, name))
       v.push_back(os);
-    assert(s->getOutputSection()->sectionIndex == UINT32_MAX);
+    assert(isa<MergeInputSection>(s) ||
+           s->getOutputSection()->sectionIndex == UINT32_MAX);
   };
 
   // For futher --emit-reloc handling code we need target output section

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Tue Sep 24 04:48:31 2019
@@ -168,6 +168,12 @@ struct InputSectionDescription : BaseCom
   // will be associated with this InputSectionDescription.
   std::vector<SectionPattern> sectionPatterns;
 
+  // Includes InputSections and MergeInputSections. Used temporarily during
+  // assignment of input sections to output sections.
+  std::vector<InputSectionBase *> sectionBases;
+
+  // Used after the finalizeInputSections() pass. MergeInputSections have been
+  // merged into MergeSyntheticSections.
   std::vector<InputSection *> sections;
 
   // Temporary record of synthetic ThunkSection instances and the pass that
@@ -226,10 +232,10 @@ class LinkerScript final {
   void expandOutputSection(uint64_t size);
   void expandMemoryRegions(uint64_t size);
 
-  std::vector<InputSection *>
+  std::vector<InputSectionBase *>
   computeInputSections(const InputSectionDescription *);
 
-  std::vector<InputSection *> createInputSectionList(OutputSection &cmd);
+  std::vector<InputSectionBase *> createInputSectionList(OutputSection &cmd);
 
   std::vector<size_t> getPhdrIndices(OutputSection *sec);
 
@@ -259,7 +265,7 @@ public:
 
   bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
   uint64_t getDot() { return dot; }
-  void discard(ArrayRef<InputSection *> v);
+  void discard(InputSectionBase *s);
 
   ExprValue getSymbolValue(StringRef name, const Twine &loc);
 

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Tue Sep 24 04:48:31 2019
@@ -83,12 +83,32 @@ static bool canMergeToProgbits(unsigned
          type == SHT_NOTE;
 }
 
-void OutputSection::addSection(InputSection *isec) {
+// Record that isec will be placed in the OutputSection. isec does not become
+// permanent until finalizeInputSections() is called. The function should not be
+// used after finalizeInputSections() is called. If you need to add an
+// InputSection post finalizeInputSections(), then you must do the following:
+//
+// 1. Find or create an InputSectionDescription to hold InputSection.
+// 2. Add the InputSection to the InputSectionDesciption::sections.
+// 3. Call commitSection(isec).
+void OutputSection::recordSection(InputSectionBase *isec) {
+  partition = isec->partition;
+  isec->parent = this;
+  if (sectionCommands.empty() ||
+      !isa<InputSectionDescription>(sectionCommands.back()))
+    sectionCommands.push_back(make<InputSectionDescription>(""));
+  auto *isd = cast<InputSectionDescription>(sectionCommands.back());
+  isd->sectionBases.push_back(isec);
+}
+
+// Update fields (type, flags, alignment, etc) according to the InputSection
+// isec. Also check whether the InputSection flags and type are consistent with
+// other InputSections.
+void OutputSection::commitSection(InputSection *isec) {
   if (!hasInputSections) {
     // If IS is the first section to be added to this section,
-    // initialize Partition, Type, Entsize and flags from IS.
+    // initialize type, entsize and flags from isec.
     hasInputSections = true;
-    partition = isec->partition;
     type = isec->type;
     entsize = isec->entsize;
     flags = isec->flags;
@@ -110,6 +130,8 @@ void OutputSection::addSection(InputSect
       type = SHT_PROGBITS;
     }
   }
+  if (noload)
+    type = SHT_NOBITS;
 
   isec->parent = this;
   uint64_t andMask =
@@ -118,6 +140,8 @@ void OutputSection::addSection(InputSect
   uint64_t andFlags = (flags & isec->flags) & andMask;
   uint64_t orFlags = (flags | isec->flags) & orMask;
   flags = andFlags | orFlags;
+  if (nonAlloc)
+    flags &= ~(uint64_t)SHF_ALLOC;
 
   alignment = std::max(alignment, isec->alignment);
 
@@ -126,15 +150,69 @@ void OutputSection::addSection(InputSect
   // set sh_entsize to 0.
   if (entsize != isec->entsize)
     entsize = 0;
+}
+
+// This function scans over the InputSectionBase list sectionBases to create
+// InputSectionDescription::sections.
+//
+// It removes MergeInputSections from the input section array and adds
+// new synthetic sections at the location of the first input section
+// that it replaces. It then finalizes each synthetic section in order
+// to compute an output offset for each piece of each input section.
+void OutputSection::finalizeInputSections() {
+  std::vector<MergeSyntheticSection *> mergeSections;
+  for (BaseCommand *base : sectionCommands) {
+    auto *cmd = dyn_cast<InputSectionDescription>(base);
+    if (!cmd)
+      continue;
+    cmd->sections.reserve(cmd->sectionBases.size());
+    for (InputSectionBase *s : cmd->sectionBases) {
+      MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
+      if (!ms) {
+        cmd->sections.push_back(cast<InputSection>(s));
+        continue;
+      }
+
+      // We do not want to handle sections that are not alive, so just remove
+      // them instead of trying to merge.
+      if (!ms->isLive())
+        continue;
+
+      auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
+        // While we could create a single synthetic section for two different
+        // values of Entsize, it is better to take Entsize into consideration.
+        //
+        // With a single synthetic section no two pieces with different Entsize
+        // could be equal, so we may as well have two sections.
+        //
+        // Using Entsize in here also allows us to propagate it to the synthetic
+        // section.
+        //
+        // SHF_STRINGS section with different alignments should not be merged.
+        return sec->flags == ms->flags && sec->entsize == ms->entsize &&
+               (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
+      });
+      if (i == mergeSections.end()) {
+        MergeSyntheticSection *syn =
+            createMergeSynthetic(name, ms->type, ms->flags, ms->alignment);
+        mergeSections.push_back(syn);
+        i = std::prev(mergeSections.end());
+        syn->entsize = ms->entsize;
+        cmd->sections.push_back(syn);
+      }
+      (*i)->addSection(ms);
+    }
 
-  if (!isec->assigned) {
-    isec->assigned = true;
-    if (sectionCommands.empty() ||
-        !isa<InputSectionDescription>(sectionCommands.back()))
-      sectionCommands.push_back(make<InputSectionDescription>(""));
-    auto *isd = cast<InputSectionDescription>(sectionCommands.back());
-    isd->sections.push_back(isec);
+    // sectionBases should not be used from this point onwards. Clear it to
+    // catch misuses.
+    cmd->sectionBases.clear();
+
+    // Some input sections may be removed from the list after ICF.
+    for (InputSection *s : cmd->sections)
+      commitSection(s);
   }
+  for (auto *ms : mergeSections)
+    ms->finalizeContents();
 }
 
 static void sortByOrder(MutableArrayRef<InputSection *> in,

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Tue Sep 24 04:48:31 2019
@@ -71,7 +71,9 @@ public:
   uint64_t addr = 0;
   uint32_t shName = 0;
 
-  void addSection(InputSection *isec);
+  void recordSection(InputSectionBase *isec);
+  void commitSection(InputSection *isec);
+  void finalizeInputSections();
 
   // The following members are normally only used in linker scripts.
   MemoryRegion *memRegion = nullptr;

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Tue Sep 24 04:48:31 2019
@@ -567,10 +567,16 @@ template <class ELFT> static void addCop
   bool isRO = isReadOnly<ELFT>(ss);
   BssSection *sec =
       make<BssSection>(isRO ? ".bss.rel.ro" : ".bss", symSize, ss.alignment);
-  if (isRO)
-    in.bssRelRo->getParent()->addSection(sec);
-  else
-    in.bss->getParent()->addSection(sec);
+  OutputSection *osec = (isRO ? in.bssRelRo : in.bss)->getParent();
+
+  // At this point, sectionBases has been migrated to sections. Append sec to
+  // sections.
+  if (osec->sectionCommands.empty() ||
+      !isa<InputSectionDescription>(osec->sectionCommands.back()))
+    osec->sectionCommands.push_back(make<InputSectionDescription>(""));
+  auto *isd = cast<InputSectionDescription>(osec->sectionCommands.back());
+  isd->sections.push_back(sec);
+  osec->commitSection(sec);
 
   // Look through the DSO's dynamic symbol table for aliases and create a
   // dynamic symbol for each one. This causes the copy relocation to correctly

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Tue Sep 24 04:48:31 2019
@@ -3125,10 +3125,9 @@ void MergeNoTailSection::finalizeContent
   });
 }
 
-static MergeSyntheticSection *createMergeSynthetic(StringRef name,
-                                                   uint32_t type,
-                                                   uint64_t flags,
-                                                   uint32_t alignment) {
+MergeSyntheticSection *elf::createMergeSynthetic(StringRef name, uint32_t type,
+                                                 uint64_t flags,
+                                                 uint32_t alignment) {
   bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2;
   if (shouldTailMerge)
     return make<MergeTailSection>(name, type, flags, alignment);
@@ -3146,63 +3145,6 @@ template <class ELFT> void elf::splitSec
   });
 }
 
-// This function scans over the inputsections to create mergeable
-// synthetic sections.
-//
-// It removes MergeInputSections from the input section array and adds
-// new synthetic sections at the location of the first input section
-// that it replaces. It then finalizes each synthetic section in order
-// to compute an output offset for each piece of each input section.
-void elf::mergeSections() {
-  std::vector<MergeSyntheticSection *> mergeSections;
-  for (InputSectionBase *&s : inputSections) {
-    MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
-    if (!ms)
-      continue;
-
-    // We do not want to handle sections that are not alive, so just remove
-    // them instead of trying to merge.
-    if (!ms->isLive()) {
-      s = nullptr;
-      continue;
-    }
-
-    StringRef outsecName = getOutputSectionName(ms);
-
-    auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
-      // While we could create a single synthetic section for two different
-      // values of Entsize, it is better to take Entsize into consideration.
-      //
-      // With a single synthetic section no two pieces with different Entsize
-      // could be equal, so we may as well have two sections.
-      //
-      // Using Entsize in here also allows us to propagate it to the synthetic
-      // section.
-      //
-      // SHF_STRINGS section with different alignments should not be merged.
-      return sec->name == outsecName && sec->flags == ms->flags &&
-             sec->entsize == ms->entsize &&
-             (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
-    });
-    if (i == mergeSections.end()) {
-      MergeSyntheticSection *syn =
-          createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment);
-      mergeSections.push_back(syn);
-      i = std::prev(mergeSections.end());
-      s = syn;
-      syn->entsize = ms->entsize;
-    } else {
-      s = nullptr;
-    }
-    (*i)->addSection(ms);
-  }
-  for (auto *ms : mergeSections)
-    ms->finalizeContents();
-
-  std::vector<InputSectionBase *> &v = inputSections;
-  v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());
-}
-
 MipsRldMapSection::MipsRldMapSection()
     : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize,
                        ".rld_map") {}

Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Tue Sep 24 04:48:31 2019
@@ -1102,8 +1102,9 @@ public:
 
 InputSection *createInterpSection();
 MergeInputSection *createCommentSection();
+MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type,
+                                            uint64_t flags, uint32_t alignment);
 template <class ELFT> void splitSections();
-void mergeSections();
 
 template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part);
 template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part);

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Tue Sep 24 04:48:31 2019
@@ -705,7 +705,7 @@ template <class ELFT> void Writer<ELFT>:
     });
     if (i == sec->sectionCommands.end())
       continue;
-    InputSection *isec = cast<InputSectionDescription>(*i)->sections[0];
+    InputSectionBase *isec = cast<InputSectionDescription>(*i)->sections[0];
 
     // Relocations are not using REL[A] section symbols.
     if (isec->type == SHT_REL || isec->type == SHT_RELA)

Added: lld/trunk/test/ELF/linkerscript/merge-output-sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/merge-output-sections.s?rev=372734&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/merge-output-sections.s (added)
+++ lld/trunk/test/ELF/linkerscript/merge-output-sections.s Tue Sep 24 04:48:31 2019
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+## SHF_MERGE sections within the same output section can be freely merged.
+# RUN: echo 'SECTIONS { .rodata : { *(.rodata.*) }}' > %t.script
+# RUN: ld.lld %t.o -T %t.script -o %t
+# RUN: llvm-readelf -x .rodata %t | FileCheck --check-prefix=SAME %s --implicit-check-not=section
+
+# SAME:      section '.rodata':
+# SAME-NEXT: 0x00000000 01000200 0300
+
+## SHF_MERGE sections with different output sections cannot be merged.
+# RUN: echo 'SECTIONS { \
+# RUN:   .rodata.foo : { *(.rodata.foo) } \
+# RUN:   .rodata.bar : { *(.rodata.bar) } \
+# RUN: }' > %t2.script
+# RUN: ld.lld %t.o -T %t2.script -o %t2
+# RUN: llvm-readelf -x .rodata.foo -x .rodata.bar %t2 | FileCheck --check-prefix=DIFF %s --implicit-check-not=section
+
+# DIFF:      section '.rodata.foo':
+# DIFF-NEXT: 0x00000000 01000200 0300
+# DIFF:      section '.rodata.bar':
+# DIFF-NEXT: 0x00000006 0100
+
+.section .rodata.foo,"aM", at progbits,2,unique,0
+.short 1
+.short 2
+.section .rodata.foo,"aM", at progbits,2,unique,1
+.short 1
+.short 3
+
+.section .rodata.bar,"aM", at progbits,2,unique,0
+.short 1
+.section .rodata.bar,"aM", at progbits,2,unique,1
+.short 1

Modified: lld/trunk/test/ELF/linkerscript/merge-sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/merge-sections.s?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/merge-sections.s (original)
+++ lld/trunk/test/ELF/linkerscript/merge-sections.s Tue Sep 24 04:48:31 2019
@@ -17,7 +17,7 @@
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   Address: 0x[[ADDR1:.*]]
 # CHECK-NEXT:   Offset: 0x[[ADDR1]]
-# CHECK-NEXT:   Size: 14
+# CHECK-NEXT:   Size: 8
 # CHECK-NEXT:   Link: 0
 # CHECK-NEXT:   Info: 0
 # CHECK-NEXT:   AddressAlignment: 2
@@ -28,7 +28,7 @@
 # CHECK-NEXT: Value: 0x[[ADDR1]]
 
 # CHECK:      Name: end
-# CHECK-NEXT: Value: 0x236
+# CHECK-NEXT: Value: 0x230
 
 # Check that we don't crash with --gc-sections
 # RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared

Modified: lld/trunk/test/ELF/merge-entsize2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/merge-entsize2.s?rev=372734&r1=372733&r2=372734&view=diff
==============================================================================
--- lld/trunk/test/ELF/merge-entsize2.s (original)
+++ lld/trunk/test/ELF/merge-entsize2.s Tue Sep 24 04:48:31 2019
@@ -6,8 +6,8 @@
 # RUN: llvm-readelf -x .cst %t | FileCheck --check-prefix=HEX %s
 
 # RUN: ld.lld -O0 -r %t.o -o %t1.o
-# RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC-R %s
-# RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX-R %s
+# RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC %s
+# RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX %s
 
 ## Check that SHF_MERGE sections with the same name, sh_flags and sh_entsize
 ## are grouped together and can be merged within the group.
@@ -17,20 +17,10 @@
 # SEC:   Name  Type     {{.*}} Size   ES Flg Lk Inf Al
 # SEC:   .cst  PROGBITS {{.*}} 000020 00  AM  0   0  8
 
-## .cst 0 and .cst 1 are merged, but emitted as a separate output section.
-# SEC-R: .cst  PROGBITS {{.*}} 00000c 04  AM  0   0  4
-# SEC-R: .cst  PROGBITS {{.*}} 000010 08  AM  0   0  8
-
 # HEX:      Hex dump of section '.cst':
 # HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 02000000 00000000
 # HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 03000000 00000000
 
-# HEX-R:      Hex dump of section '.cst':
-# HEX-R-NEXT: 0x00000000 01000000 00000000 02000000
-# HEX-R-EMPTY:
-# HEX-R-NEXT: Hex dump of section '.cst':
-# HEX-R-NEXT: 0x00000000 01000000 00000000 03000000 00000000
-
 .section .cst,"aM", at progbits,4,unique,0
 .align 2
 .long 1




More information about the llvm-commits mailing list