[BOLT] Section-handling refactoring/overhaul
authorMaksim Panchenko <maks@fb.com>
Thu, 22 Sep 2022 19:05:12 +0000 (12:05 -0700)
committerMaksim Panchenko <maks@fb.com>
Fri, 14 Oct 2022 06:10:39 +0000 (23:10 -0700)
Simplify the logic of handling sections in BOLT. This change brings more
direct and predictable mapping of BinarySection instances to sections in
the input and output files.

* Only sections from the input binary will have a non-null SectionRef.
  When a new section is created as a copy of the input section,
  its SectionRef is reset to null.

* RewriteInstance::getOutputSectionName() is removed as the section name
  in the output file is now defined by BinarySection::getOutputName().

* Querying BinaryContext for sections by name uses their original name.
  E.g., getUniqueSectionByName(".rodata") will return the original
  section even if the new .rodata section was created.

* Input file sections (with relocations applied) are emitted via MC with
  ".bolt.org" prefix. However, their name in the output binary is
  unchanged unless a new section with the same name is created.

* New sections are emitted internally with ".bolt.new" prefix if there's
  a name conflict with an input file section. Their original name is
  preserved in the output file.

* Section header string table is properly populated with section names
  that are actually used. Previously we used to include discarded
  section names as well.

* Fix the problem when dynamic relocations were propagated to a new
  section with a name that matched a section in the input binary.
  E.g., the new .rodata with jump tables had dynamic relocations from
  the original .rodata.

Reviewed By: rafauler

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

13 files changed:
bolt/include/bolt/Core/BinaryContext.h
bolt/include/bolt/Core/BinarySection.h
bolt/include/bolt/Rewrite/ExecutableFileMemoryManager.h
bolt/include/bolt/Rewrite/MachORewriteInstance.h
bolt/include/bolt/Rewrite/RewriteInstance.h
bolt/lib/Core/BinaryContext.cpp
bolt/lib/Core/BinaryEmitter.cpp
bolt/lib/Core/BinarySection.cpp
bolt/lib/Passes/ReorderData.cpp
bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp
bolt/lib/Rewrite/MachORewriteInstance.cpp
bolt/lib/Rewrite/RewriteInstance.cpp
bolt/test/X86/dynrelocs.s

index b97177c..3c99426 100644 (file)
@@ -179,6 +179,10 @@ class BinaryContext {
   using NameToSectionMapType = std::multimap<std::string, BinarySection *>;
   NameToSectionMapType NameToSection;
 
+  /// Map section references to BinarySection for matching sections in the
+  /// input file to internal section representation.
+  DenseMap<SectionRef, BinarySection *> SectionRefToBinarySection;
+
   /// Low level section registration.
   BinarySection &registerSection(BinarySection *Section);
 
@@ -224,6 +228,9 @@ class BinaryContext {
   /// DWARF line info for CUs.
   std::map<unsigned, DwarfLineTable> DwarfLineTablesCUMap;
 
+  /// Internal helper for removing section name from a lookup table.
+  void deregisterSectionName(const BinarySection &Section);
+
 public:
   static Expected<std::unique_ptr<BinaryContext>>
   createBinaryContext(const ObjectFile *File, bool IsPIC,
@@ -951,13 +958,13 @@ public:
   BinarySection &registerSection(SectionRef Section);
 
   /// Register a copy of /p OriginalSection under a different name.
-  BinarySection &registerSection(StringRef SectionName,
+  BinarySection &registerSection(const Twine &SectionName,
                                  const BinarySection &OriginalSection);
 
   /// Register or update the information for the section with the given
   /// /p Name.  If the section already exists, the information in the
   /// section will be updated with the new data.
-  BinarySection &registerOrUpdateSection(StringRef Name, unsigned ELFType,
+  BinarySection &registerOrUpdateSection(const Twine &Name, unsigned ELFType,
                                          unsigned ELFFlags,
                                          uint8_t *Data = nullptr,
                                          uint64_t Size = 0,
@@ -967,7 +974,7 @@ public:
   /// with the given /p Name.  If the section already exists, the
   /// information in the section will be updated with the new data.
   BinarySection &
-  registerOrUpdateNoteSection(StringRef Name, uint8_t *Data = nullptr,
+  registerOrUpdateNoteSection(const Twine &Name, uint8_t *Data = nullptr,
                               uint64_t Size = 0, unsigned Alignment = 1,
                               bool IsReadOnly = true,
                               unsigned ELFType = ELF::SHT_PROGBITS) {
@@ -976,10 +983,16 @@ public:
                                    Size, Alignment);
   }
 
+  /// Remove sections that were preregistered but never used.
+  void deregisterUnusedSections();
+
   /// Remove the given /p Section from the set of all sections.  Return
   /// true if the section was removed (and deleted), otherwise false.
   bool deregisterSection(BinarySection &Section);
 
+  /// Re-register \p Section under the \p NewName.
+  void renameSection(BinarySection &Section, const Twine &NewName);
+
   /// Iterate over all registered sections.
   iterator_range<FilteredSectionIterator> sections() {
     auto notNull = [](const SectionIterator &Itr) { return (bool)*Itr; };
@@ -1073,20 +1086,26 @@ public:
     return const_cast<BinaryContext *>(this)->getSectionForAddress(Address);
   }
 
+  /// Return internal section representation for a section in a file.
+  BinarySection *getSectionForSectionRef(SectionRef Section) const {
+    return SectionRefToBinarySection.lookup(Section);
+  }
+
   /// Return section(s) associated with given \p Name.
   iterator_range<NameToSectionMapType::iterator>
-  getSectionByName(StringRef Name) {
-    return make_range(NameToSection.equal_range(std::string(Name)));
+  getSectionByName(const Twine &Name) {
+    return make_range(NameToSection.equal_range(Name.str()));
   }
   iterator_range<NameToSectionMapType::const_iterator>
-  getSectionByName(StringRef Name) const {
-    return make_range(NameToSection.equal_range(std::string(Name)));
+  getSectionByName(const Twine &Name) const {
+    return make_range(NameToSection.equal_range(Name.str()));
   }
 
   /// Return the unique section associated with given \p Name.
   /// If there is more than one section with the same name, return an error
   /// object.
-  ErrorOr<BinarySection &> getUniqueSectionByName(StringRef SectionName) const {
+  ErrorOr<BinarySection &>
+  getUniqueSectionByName(const Twine &SectionName) const {
     auto Sections = getSectionByName(SectionName);
     if (Sections.begin() != Sections.end() &&
         std::next(Sections.begin()) == Sections.end())
index 2c6916a..ca88783 100644 (file)
@@ -48,7 +48,7 @@ class BinarySection {
 
   BinaryContext &BC;           // Owning BinaryContext
   std::string Name;            // Section name
-  const SectionRef Section;    // SectionRef (may be null)
+  const SectionRef Section;    // SectionRef for input binary sections.
   StringRef Contents;          // Input section contents
   const uint64_t Address;      // Address of section in input binary (may be 0)
   const uint64_t Size;         // Input section size
@@ -144,14 +144,14 @@ class BinarySection {
 
 public:
   /// Copy a section.
-  explicit BinarySection(BinaryContext &BC, StringRef Name,
+  explicit BinarySection(BinaryContext &BC, const Twine &Name,
                          const BinarySection &Section)
-      : BC(BC), Name(Name), Section(Section.getSectionRef()),
+      : BC(BC), Name(Name.str()), Section(SectionRef()),
         Contents(Section.getContents()), Address(Section.getAddress()),
         Size(Section.getSize()), Alignment(Section.getAlignment()),
         ELFType(Section.getELFType()), ELFFlags(Section.getELFFlags()),
         Relocations(Section.Relocations),
-        PendingRelocations(Section.PendingRelocations), OutputName(Name),
+        PendingRelocations(Section.PendingRelocations), OutputName(Name.str()),
         SectionNumber(++Count) {}
 
   BinarySection(BinaryContext &BC, SectionRef Section)
@@ -172,12 +172,13 @@ public:
   }
 
   // TODO: pass Data as StringRef/ArrayRef? use StringRef::copy method.
-  BinarySection(BinaryContext &BC, StringRef Name, uint8_t *Data, uint64_t Size,
-                unsigned Alignment, unsigned ELFType, unsigned ELFFlags)
-      : BC(BC), Name(Name),
+  BinarySection(BinaryContext &BC, const Twine &Name, uint8_t *Data,
+                uint64_t Size, unsigned Alignment, unsigned ELFType,
+                unsigned ELFFlags)
+      : BC(BC), Name(Name.str()),
         Contents(reinterpret_cast<const char *>(Data), Data ? Size : 0),
         Address(0), Size(Size), Alignment(Alignment), ELFType(ELFType),
-        ELFFlags(ELFFlags), IsFinalized(true), OutputName(Name),
+        ELFFlags(ELFFlags), IsFinalized(true), OutputName(Name.str()),
         OutputSize(Size), OutputContents(Contents), SectionNumber(++Count) {
     assert(Alignment > 0 && "section alignment must be > 0");
   }
@@ -221,9 +222,9 @@ public:
       return hasSectionRef() > Other.hasSectionRef();
 
     // Compare allocatable input sections by their address.
-    if (getAddress() != Other.getAddress())
+    if (hasSectionRef() && getAddress() != Other.getAddress())
       return getAddress() < Other.getAddress();
-    if (getAddress() && getSize() != Other.getSize())
+    if (hasSectionRef() && getAddress() && getSize() != Other.getSize())
       return getSize() < Other.getSize();
 
     // Code before data.
@@ -435,6 +436,7 @@ public:
     return SectionID;
   }
   bool hasValidSectionID() const { return SectionID != -1u; }
+  bool hasValidIndex() { return Index != 0; }
   uint32_t getIndex() const { return Index; }
 
   // mutation
@@ -445,12 +447,12 @@ public:
     SectionID = ID;
   }
   void setIndex(uint32_t I) { Index = I; }
-  void setOutputName(StringRef Name) { OutputName = std::string(Name); }
+  void setOutputName(const Twine &Name) { OutputName = Name.str(); }
   void setAnonymous(bool Flag) { IsAnonymous = Flag; }
 
-  /// Emit the section as data, possibly with relocations. Use name \p NewName
-  //  for the section during emission if non-empty.
-  void emitAsData(MCStreamer &Streamer, StringRef NewName = StringRef()) const;
+  /// Emit the section as data, possibly with relocations.
+  /// Use name \p SectionName for the section during the emission.
+  void emitAsData(MCStreamer &Streamer, const Twine &SectionName) const;
 
   using SymbolResolverFuncTy = llvm::function_ref<uint64_t(const MCSymbol *)>;
 
@@ -459,6 +461,13 @@ public:
   void flushPendingRelocations(raw_pwrite_stream &OS,
                                SymbolResolverFuncTy Resolver);
 
+  /// Change contents of the section.
+  void updateContents(const uint8_t *Data, size_t NewSize) {
+    OutputContents = StringRef(reinterpret_cast<const char *>(Data), NewSize);
+    OutputSize = NewSize;
+    IsFinalized = true;
+  }
+
   /// Reorder the contents of this section according to /p Order.  If
   /// /p Inplace is true, the entire contents of the section is reordered,
   /// otherwise the new contents contain only the reordered data.
index 3549f3d..347d5c9 100644 (file)
@@ -35,6 +35,12 @@ private:
   };
   SmallVector<AllocInfo, 8> AllocatedSections;
 
+  // All new sections will be identified by the following prefix.
+  std::string NewSecPrefix;
+
+  // Name prefix used for sections from the input.
+  std::string OrgSecPrefix;
+
 public:
   // Our linker's main purpose is to handle a single object file, created
   // by RewriteInstance after reading the input binary and reordering it.
@@ -86,6 +92,10 @@ public:
   void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
                         size_t Size) override {}
   void deregisterEHFrames() override {}
+
+  /// Section name management.
+  void setNewSecPrefix(StringRef Prefix) { NewSecPrefix = Prefix; }
+  void setOrgSecPrefix(StringRef Prefix) { OrgSecPrefix = Prefix; }
 };
 
 } // namespace bolt
index 0d3b72d..27ca6ff 100644 (file)
@@ -46,6 +46,7 @@ class MachORewriteInstance {
   void processProfileDataPreCFG();
   void processProfileData();
 
+  static StringRef getNewSecPrefix() { return ".bolt.new"; }
   static StringRef getOrgSecPrefix() { return ".bolt.org"; }
 
   void mapInstrumentationSection(StringRef SectionName);
index 67c2ab9..c50625f 100644 (file)
@@ -169,6 +169,8 @@ private:
 
   void postProcessFunctions();
 
+  void preregisterSections();
+
   /// Run optimizations that operate at the binary, or post-linker, level.
   void runOptimizationPasses();
 
@@ -199,10 +201,13 @@ private:
   std::vector<BinarySection *> getCodeSections();
 
   /// Map all sections to their final addresses.
-  void mapCodeSections(RuntimeDyld &RTDyld);
-  void mapDataSections(RuntimeDyld &RTDyld);
   void mapFileSections(RuntimeDyld &RTDyld);
-  void mapExtraSections(RuntimeDyld &RTDyld);
+
+  /// Map code sections generated by BOLT.
+  void mapCodeSections(RuntimeDyld &RTDyld);
+
+  /// Map the rest of allocatable sections.
+  void mapAllocatableSections(RuntimeDyld &RTDyld);
 
   /// Update output object's values based on the final \p Layout.
   void updateOutputValues(const MCAsmLayout &Layout);
@@ -306,11 +311,6 @@ private:
   /// Finalize memory image of section header string table.
   ELF_FUNCTION(void, finalizeSectionStringTable);
 
-  /// Return a name of the input file section in the output file.
-  template <typename ELFObjType, typename ELFShdrTy>
-  std::string getOutputSectionName(const ELFObjType &Obj,
-                                   const ELFShdrTy &Section);
-
   /// Return a list of all sections to include in the output binary.
   /// Populate \p NewSectionIndex with a map of input to output indices.
   template <typename ELFT>
@@ -419,6 +419,11 @@ private:
   /// Alignment value used for .eh_frame_hdr.
   static constexpr uint64_t EHFrameHdrAlign = 4;
 
+  /// Sections created by BOLT will have an internal name that starts with the
+  /// following prefix. Note that the prefix is used for a section lookup
+  /// internally and the section name in the output might be different.
+  static StringRef getNewSecPrefix() { return ".bolt.new"; }
+
   /// String to be added before the original section name.
   ///
   /// When BOLT creates a new section with the same name as the one in the
@@ -426,9 +431,12 @@ private:
   /// will be added to the name of the original section.
   static StringRef getOrgSecPrefix() { return ".bolt.org"; }
 
-  /// Section name used for new code.
+  /// Section name used for extra BOLT code in addition to .text.
   static StringRef getBOLTTextSectionName() { return ".bolt.text"; }
 
+  /// Common section names.
+  static StringRef getEHFrameSectionName() { return ".eh_frame"; }
+
   /// An instance of the input binary we are processing, externally owned.
   llvm::object::ELFObjectFileBase *InputFile;
 
@@ -563,6 +571,12 @@ private:
   /// Contains information about pseudo probe details, like its address
   ErrorOr<BinarySection &> PseudoProbeSection{std::errc::bad_address};
 
+  /// Helper for accessing sections by name.
+  BinarySection *getSection(const Twine &Name) {
+    ErrorOr<BinarySection &> ErrOrSection = BC->getUniqueSectionByName(Name);
+    return ErrOrSection ? &ErrOrSection.get() : nullptr;
+  }
+
   /// A reference to the build-id bytes in the original binary
   StringRef BuildID;
 
@@ -576,7 +590,6 @@ private:
 
   /// Section header string table.
   StringTableBuilder SHStrTab;
-  std::vector<std::string> SHStrTabPool;
 
   /// A rewrite of strtab
   std::string NewStrTab;
index bba5e49..f3f55b9 100644 (file)
@@ -1932,6 +1932,10 @@ BinarySection &BinaryContext::registerSection(BinarySection *Section) {
     AddressToSection.insert(std::make_pair(Section->getAddress(), Section));
   NameToSection.insert(
       std::make_pair(std::string(Section->getName()), Section));
+  if (Section->hasSectionRef())
+    SectionRefToBinarySection.insert(
+        std::make_pair(Section->getSectionRef(), Section));
+
   LLVM_DEBUG(dbgs() << "BOLT-DEBUG: registering " << *Section << "\n");
   return *Section;
 }
@@ -1941,14 +1945,14 @@ BinarySection &BinaryContext::registerSection(SectionRef Section) {
 }
 
 BinarySection &
-BinaryContext::registerSection(StringRef SectionName,
+BinaryContext::registerSection(const Twine &SectionName,
                                const BinarySection &OriginalSection) {
   return registerSection(
       new BinarySection(*this, SectionName, OriginalSection));
 }
 
 BinarySection &
-BinaryContext::registerOrUpdateSection(StringRef Name, unsigned ELFType,
+BinaryContext::registerOrUpdateSection(const Twine &Name, unsigned ELFType,
                                        unsigned ELFFlags, uint8_t *Data,
                                        uint64_t Size, unsigned Alignment) {
   auto NamedSections = getSectionByName(Name);
@@ -1973,6 +1977,35 @@ BinaryContext::registerOrUpdateSection(StringRef Name, unsigned ELFType,
       new BinarySection(*this, Name, Data, Size, Alignment, ELFType, ELFFlags));
 }
 
+void BinaryContext::deregisterSectionName(const BinarySection &Section) {
+  auto NameRange = NameToSection.equal_range(Section.getName().str());
+  while (NameRange.first != NameRange.second) {
+    if (NameRange.first->second == &Section) {
+      NameToSection.erase(NameRange.first);
+      break;
+    }
+    ++NameRange.first;
+  }
+}
+
+void BinaryContext::deregisterUnusedSections() {
+  ErrorOr<BinarySection &> AbsSection = getUniqueSectionByName("<absolute>");
+  for (auto SI = Sections.begin(); SI != Sections.end();) {
+    BinarySection *Section = *SI;
+    if (Section->hasSectionRef() || Section->getOutputSize() ||
+        (AbsSection && Section == &AbsSection.get())) {
+      ++SI;
+      continue;
+    }
+
+    LLVM_DEBUG(dbgs() << "LLVM-DEBUG: deregistering " << Section->getName()
+                      << '\n';);
+    deregisterSectionName(*Section);
+    SI = Sections.erase(SI);
+    delete Section;
+  }
+}
+
 bool BinaryContext::deregisterSection(BinarySection &Section) {
   BinarySection *SectionPtr = &Section;
   auto Itr = Sections.find(SectionPtr);
@@ -1986,16 +2019,7 @@ bool BinaryContext::deregisterSection(BinarySection &Section) {
       ++Range.first;
     }
 
-    auto NameRange =
-        NameToSection.equal_range(std::string(SectionPtr->getName()));
-    while (NameRange.first != NameRange.second) {
-      if (NameRange.first->second == SectionPtr) {
-        NameToSection.erase(NameRange.first);
-        break;
-      }
-      ++NameRange.first;
-    }
-
+    deregisterSectionName(*SectionPtr);
     Sections.erase(Itr);
     delete SectionPtr;
     return true;
@@ -2003,6 +2027,23 @@ bool BinaryContext::deregisterSection(BinarySection &Section) {
   return false;
 }
 
+void BinaryContext::renameSection(BinarySection &Section,
+                                  const Twine &NewName) {
+  auto Itr = Sections.find(&Section);
+  assert(Itr != Sections.end() && "Section must exist to be renamed.");
+  Sections.erase(Itr);
+
+  deregisterSectionName(Section);
+
+  Section.Name = NewName.str();
+  Section.setOutputName(NewName);
+
+  NameToSection.insert(std::make_pair(NewName.str(), &Section));
+
+  // Reinsert with the new name.
+  Sections.insert(&Section);
+}
+
 void BinaryContext::printSections(raw_ostream &OS) const {
   for (BinarySection *const &Section : Sections)
     OS << "BOLT-INFO: " << *Section << "\n";
index f618619..c81dcc3 100644 (file)
@@ -801,11 +801,12 @@ void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection,
   for (MCSymbol *Entry : JT.Entries) {
     auto LI = JT.Labels.find(Offset);
     if (LI != JT.Labels.end()) {
-      LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitting jump table "
-                        << LI->second->getName()
-                        << " (originally was at address 0x"
-                        << Twine::utohexstr(JT.getAddress() + Offset)
-                        << (Offset ? "as part of larger jump table\n" : "\n"));
+      LLVM_DEBUG({
+        dbgs() << "BOLT-DEBUG: emitting jump table " << LI->second->getName()
+               << " (originally was at address 0x"
+               << Twine::utohexstr(JT.getAddress() + Offset)
+               << (Offset ? ") as part of larger jump table\n" : ")\n");
+      });
       if (!LabelCounts.empty()) {
         LLVM_DEBUG(dbgs() << "BOLT-DEBUG: jump table count: "
                           << LabelCounts[LI->second] << '\n');
@@ -1156,14 +1157,11 @@ void BinaryEmitter::emitDebugLineInfoForUnprocessedCUs() {
 
 void BinaryEmitter::emitDataSections(StringRef OrgSecPrefix) {
   for (BinarySection &Section : BC.sections()) {
-    if (!Section.hasRelocations() || !Section.hasSectionRef())
+    if (!Section.hasRelocations())
       continue;
 
-    StringRef SectionName = Section.getName();
-    std::string EmitName = Section.isReordered()
-                               ? std::string(Section.getOutputName())
-                               : OrgSecPrefix.str() + std::string(SectionName);
-    Section.emitAsData(Streamer, EmitName);
+    StringRef Prefix = Section.hasSectionRef() ? OrgSecPrefix : "";
+    Section.emitAsData(Streamer, Prefix + Section.getName());
     Section.clearRelocations();
   }
 }
index dfdec01..13acd42 100644 (file)
@@ -67,8 +67,8 @@ BinarySection::hash(const BinaryData &BD,
   return Hash;
 }
 
-void BinarySection::emitAsData(MCStreamer &Streamer, StringRef NewName) const {
-  StringRef SectionName = !NewName.empty() ? NewName : getName();
+void BinarySection::emitAsData(MCStreamer &Streamer,
+                               const Twine &SectionName) const {
   StringRef SectionContents = getContents();
   MCSectionELF *ELFSection =
       BC.Ctx->getELFSection(SectionName, getELFType(), getELFFlags());
index 84bf460..f12a3ea 100644 (file)
@@ -500,19 +500,21 @@ void ReorderData::runOnFunctions(BinaryContext &BC) {
                << Section->getName() << " falling back to splitting "
                << "instead of in-place reordering.\n";
 
-      // Copy original section to <section name>.cold.
-      BinarySection &Cold = BC.registerSection(
-          std::string(Section->getName()) + ".cold", *Section);
+      // Rename sections.
+      BinarySection &Hot =
+          BC.registerSection(Section->getName() + ".hot", *Section);
+      Hot.setOutputName(Section->getName());
+      Section->setOutputName(".bolt.org" + Section->getName());
 
       // Reorder contents of original section.
-      setSectionOrder(BC, *Section, Order.begin(), SplitPoint);
+      setSectionOrder(BC, Hot, Order.begin(), SplitPoint);
 
       // This keeps the original data from thinking it has been moved.
       for (std::pair<const uint64_t, BinaryData *> &Entry :
            BC.getBinaryDataForSection(*Section)) {
         if (!Entry.second->isMoved()) {
-          Entry.second->setSection(Cold);
-          Entry.second->setOutputSection(Cold);
+          Entry.second->setSection(*Section);
+          Entry.second->setOutputSection(*Section);
         }
       }
     } else {
index 68695d1..8c41ca9 100644 (file)
@@ -55,19 +55,50 @@ uint8_t *ExecutableFileMemoryManager::allocateSection(
     }
   }
 
-  BinarySection &Section = BC.registerOrUpdateSection(
-      SectionName, ELF::SHT_PROGBITS,
-      BinarySection::getFlags(IsReadOnly, IsCode, true), Ret, Size, Alignment);
-  Section.setSectionID(SectionID);
-  assert(Section.isAllocatable() &&
-         "verify that allocatable is marked as allocatable");
-
-  LLVM_DEBUG(
-      dbgs() << "BOLT: allocating "
-             << (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
-             << " section : " << SectionName << " with size " << Size
-             << ", alignment " << Alignment << " at " << Ret
-             << ", ID = " << SectionID << "\n");
+  BinarySection *Section = nullptr;
+  if (!OrgSecPrefix.empty() && SectionName.startswith(OrgSecPrefix)) {
+    // Update the original section contents.
+    ErrorOr<BinarySection &> OrgSection =
+        BC.getUniqueSectionByName(SectionName.substr(OrgSecPrefix.length()));
+    assert(OrgSection && OrgSection->isAllocatable() &&
+           "Original section must exist and be allocatable.");
+
+    Section = &OrgSection.get();
+    Section->updateContents(Ret, Size);
+  } else {
+    // If the input contains a section with the section name, rename it in the
+    // output file to avoid the section name conflict and emit the new section
+    // under a unique internal name.
+    ErrorOr<BinarySection &> OrgSection =
+        BC.getUniqueSectionByName(SectionName);
+    bool UsePrefix = false;
+    if (OrgSection && OrgSection->hasSectionRef()) {
+      OrgSection->setOutputName(OrgSecPrefix + SectionName);
+      UsePrefix = true;
+    }
+
+    // Register the new section under a unique name to avoid name collision with
+    // sections in the input file.
+    BinarySection &NewSection = BC.registerOrUpdateSection(
+        UsePrefix ? NewSecPrefix + SectionName : SectionName, ELF::SHT_PROGBITS,
+        BinarySection::getFlags(IsReadOnly, IsCode, true), Ret, Size,
+        Alignment);
+    if (UsePrefix)
+      NewSection.setOutputName(SectionName);
+    Section = &NewSection;
+  }
+
+  LLVM_DEBUG({
+    dbgs() << "BOLT: allocating "
+           << (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
+           << " section : " << Section->getOutputName() << " ("
+           << Section->getName() << ")"
+           << " with size " << Size << ", alignment " << Alignment << " at "
+           << Ret << ", ID = " << SectionID << "\n";
+  });
+
+  Section->setSectionID(SectionID);
+
   return Ret;
 }
 
index de890eb..0dfc4fd 100644 (file)
@@ -508,6 +508,8 @@ void MachORewriteInstance::emitAndLink() {
       static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler());
 
   BC->EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false));
+  BC->EFMM->setOrgSecPrefix(getOrgSecPrefix());
+  BC->EFMM->setNewSecPrefix(getNewSecPrefix());
 
   RTDyld.reset(new decltype(RTDyld)::element_type(*BC->EFMM, Resolver));
   RTDyld->setProcessAllSections(true);
index 53ce8d1..3109ef4 100644 (file)
@@ -412,6 +412,8 @@ Error RewriteInstance::discoverStorage() {
   // same size seen in the input binary, in case this section is a copy
   // of the original one seen in the binary.
   BC->EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false));
+  BC->EFMM->setNewSecPrefix(getNewSecPrefix());
+  BC->EFMM->setOrgSecPrefix(getOrgSecPrefix());
 
   auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
   const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile();
@@ -751,6 +753,8 @@ Error RewriteInstance::run() {
   if (opts::DiffOnly)
     return Error::success();
 
+  preregisterSections();
+
   runOptimizationPasses();
 
   emitAndLink();
@@ -1505,8 +1509,12 @@ void RewriteInstance::adjustFunctionBoundaries() {
 }
 
 void RewriteInstance::relocateEHFrameSection() {
-  assert(EHFrameSection && "non-empty .eh_frame section expected");
+  assert(EHFrameSection && "Non-empty .eh_frame section expected.");
 
+  BinarySection *RelocatedEHFrameSection =
+      getSection(".relocated" + getEHFrameSectionName());
+  assert(RelocatedEHFrameSection &&
+         "Relocated eh_frame section should be preregistered.");
   DWARFDataExtractor DE(EHFrameSection->getContents(),
                         BC->AsmInfo->isLittleEndian(),
                         BC->AsmInfo->getCodePointerSize());
@@ -1543,7 +1551,7 @@ void RewriteInstance::relocateEHFrameSection() {
     // Create a relocation against an absolute value since the goal is to
     // preserve the contents of the section independent of the new values
     // of referenced symbols.
-    EHFrameSection->addRelocation(Offset, nullptr, RelType, Value);
+    RelocatedEHFrameSection->addRelocation(Offset, nullptr, RelType, Value);
   };
 
   Error E = EHFrameParser::parse(DE, EHFrameSection->getAddress(), createReloc);
@@ -1571,21 +1579,18 @@ Error RewriteInstance::readSpecialSections() {
     check_error(SectionNameOrErr.takeError(), "cannot get section name");
     StringRef SectionName = *SectionNameOrErr;
 
-    // Only register sections with names.
-    if (!SectionName.empty()) {
-      if (Error E = Section.getContents().takeError())
-        return E;
-      BC->registerSection(Section);
-      LLVM_DEBUG(
-          dbgs() << "BOLT-DEBUG: registering section " << SectionName << " @ 0x"
-                 << Twine::utohexstr(Section.getAddress()) << ":0x"
-                 << Twine::utohexstr(Section.getAddress() + Section.getSize())
-                 << "\n");
-      if (isDebugSection(SectionName))
-        HasDebugInfo = true;
-      if (isKSymtabSection(SectionName))
-        opts::LinuxKernelMode = true;
-    }
+    if (Error E = Section.getContents().takeError())
+      return E;
+    BC->registerSection(Section);
+    LLVM_DEBUG(
+        dbgs() << "BOLT-DEBUG: registering section " << SectionName << " @ 0x"
+               << Twine::utohexstr(Section.getAddress()) << ":0x"
+               << Twine::utohexstr(Section.getAddress() + Section.getSize())
+               << "\n");
+    if (isDebugSection(SectionName))
+      HasDebugInfo = true;
+    if (isKSymtabSection(SectionName))
+      opts::LinuxKernelMode = true;
   }
 
   if (HasDebugInfo && !opts::UpdateDebugSections && !opts::AggregateOnly) {
@@ -3093,6 +3098,26 @@ public:
 
 } // anonymous namespace
 
+void RewriteInstance::preregisterSections() {
+  // Preregister sections before emission to set their order in the output.
+  const unsigned ROFlags = BinarySection::getFlags(/*IsReadOnly*/ true,
+                                                   /*IsText*/ false,
+                                                   /*IsAllocatable*/ true);
+  if (BinarySection *EHFrameSection = getSection(getEHFrameSectionName())) {
+    // New .eh_frame.
+    BC->registerOrUpdateSection(getNewSecPrefix() + getEHFrameSectionName(),
+                                ELF::SHT_PROGBITS, ROFlags);
+    // Fully register a relocatable copy of the original .eh_frame.
+    BC->registerSection(".relocated.eh_frame", *EHFrameSection);
+  }
+  BC->registerOrUpdateSection(getNewSecPrefix() + ".gcc_except_table",
+                              ELF::SHT_PROGBITS, ROFlags);
+  BC->registerOrUpdateSection(getNewSecPrefix() + ".rodata", ELF::SHT_PROGBITS,
+                              ROFlags);
+  BC->registerOrUpdateSection(getNewSecPrefix() + ".rodata.cold",
+                              ELF::SHT_PROGBITS, ROFlags);
+}
+
 void RewriteInstance::emitAndLink() {
   NamedRegionTimer T("emitAndLink", "emit and link", TimerGroupName,
                      TimerGroupDesc, opts::TimeRewrite);
@@ -3134,6 +3159,11 @@ void RewriteInstance::emitAndLink() {
     exit(1);
   }
 
+  ErrorOr<BinarySection &> TextSection =
+      BC->getUniqueSectionByName(BC->getMainCodeSectionName());
+  if (BC->HasRelocations && TextSection)
+    BC->renameSection(*TextSection, getOrgSecPrefix() + ".text");
+
   //////////////////////////////////////////////////////////////////////////////
   // Assign addresses to new sections.
   //////////////////////////////////////////////////////////////////////////////
@@ -3175,7 +3205,8 @@ void RewriteInstance::emitAndLink() {
 
   if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary())
     RtLibrary->link(*BC, ToolPath, *RTDyld, [this](RuntimeDyld &R) {
-      this->mapExtraSections(*RTDyld);
+      // Map newly registered sections.
+      this->mapAllocatableSections(*RTDyld);
     });
 
   // Once the code is emitted, we can rename function sections to actual
@@ -3562,8 +3593,28 @@ void RewriteInstance::updateLKMarkers() {
 }
 
 void RewriteInstance::mapFileSections(RuntimeDyld &RTDyld) {
+  BC->deregisterUnusedSections();
+
+  // If no new .eh_frame was written, remove relocated original .eh_frame.
+  BinarySection *RelocatedEHFrameSection =
+      getSection(".relocated" + getEHFrameSectionName());
+  if (RelocatedEHFrameSection && RelocatedEHFrameSection->hasValidSectionID()) {
+    BinarySection *NewEHFrameSection =
+        getSection(getNewSecPrefix() + getEHFrameSectionName());
+    if (!NewEHFrameSection || !NewEHFrameSection->isFinalized()) {
+      // RTDyld will still have to process relocations for the section, hence
+      // we need to assign it the address that wouldn't result in relocation
+      // processing failure.
+      RTDyld.reassignSectionAddress(RelocatedEHFrameSection->getSectionID(),
+                                    NextAvailableAddress);
+      BC->deregisterSection(*RelocatedEHFrameSection);
+    }
+  }
+
   mapCodeSections(RTDyld);
-  mapDataSections(RTDyld);
+
+  // Map the rest of the sections.
+  mapAllocatableSections(RTDyld);
 }
 
 std::vector<BinarySection *> RewriteInstance::getCodeSections() {
@@ -3722,7 +3773,7 @@ void RewriteInstance::mapCodeSections(RuntimeDyld &RTDyld) {
         BinarySection &Section = JT->getOutputSection();
         Section.setOutputAddress(JT->getAddress());
         Section.setOutputFileOffset(getFileOffsetForAddress(JT->getAddress()));
-        LLVM_DEBUG(dbgs() << "BOLT-DEBUG: mapping " << Section.getName()
+        LLVM_DEBUG(dbgs() << "BOLT-DEBUG: mapping JT " << Section.getName()
                           << " to 0x" << Twine::utohexstr(JT->getAddress())
                           << '\n');
         RTDyld.reassignSectionAddress(Section.getSectionID(), JT->getAddress());
@@ -3749,6 +3800,7 @@ void RewriteInstance::mapCodeSections(RuntimeDyld &RTDyld) {
       FF.setImageAddress(0);
       FF.setImageSize(0);
       FF.setFileOffset(0);
+      BC->deregisterSection(*ColdSection);
     } else {
       FF.setAddress(NextAvailableAddress);
       FF.setImageAddress(ColdSection->getAllocAddress());
@@ -3788,101 +3840,56 @@ void RewriteInstance::mapCodeSections(RuntimeDyld &RTDyld) {
   }
 }
 
-void RewriteInstance::mapDataSections(RuntimeDyld &RTDyld) {
-  // Map special sections to their addresses in the output image.
-  // These are the sections that we generate via MCStreamer.
-  // The order is important.
-  std::vector<std::string> Sections = {
-      ".eh_frame", Twine(getOrgSecPrefix(), ".eh_frame").str(),
-      ".gcc_except_table", ".rodata", ".rodata.cold"};
-  if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary())
-    RtLibrary->addRuntimeLibSections(Sections);
-
-  if (!EHFrameSection || !EHFrameSection->isFinalized()) {
-    ErrorOr<BinarySection &> OldEHFrameSection =
-        BC->getUniqueSectionByName(Twine(getOrgSecPrefix(), ".eh_frame").str());
-    if (OldEHFrameSection) {
-      RTDyld.reassignSectionAddress(OldEHFrameSection->getSectionID(),
-                                    NextAvailableAddress);
-      BC->deregisterSection(*OldEHFrameSection);
-    }
-  }
-
-  for (std::string &SectionName : Sections) {
-    ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName);
-    if (!Section || !Section->isAllocatable() || !Section->isFinalized())
-      continue;
-    NextAvailableAddress =
-        alignTo(NextAvailableAddress, Section->getAlignment());
-    LLVM_DEBUG(dbgs() << "BOLT: mapping section " << SectionName << " (0x"
-                      << Twine::utohexstr(Section->getAllocAddress())
-                      << ") to 0x" << Twine::utohexstr(NextAvailableAddress)
-                      << ":0x"
-                      << Twine::utohexstr(NextAvailableAddress +
-                                          Section->getOutputSize())
-                      << '\n');
+void RewriteInstance::mapAllocatableSections(RuntimeDyld &RTDyld) {
+  // Allocate read-only sections first, then writable sections.
+  enum : uint8_t { ST_READONLY, ST_READWRITE };
+  for (uint8_t SType = ST_READONLY; SType <= ST_READWRITE; ++SType) {
+    for (BinarySection &Section : BC->allocatableSections()) {
+      if (!Section.hasValidSectionID())
+        continue;
 
-    RTDyld.reassignSectionAddress(Section->getSectionID(),
-                                  NextAvailableAddress);
-    Section->setOutputAddress(NextAvailableAddress);
-    Section->setOutputFileOffset(getFileOffsetForAddress(NextAvailableAddress));
+      if (Section.isReadOnly() != (SType == ST_READONLY))
+        continue;
 
-    NextAvailableAddress += Section->getOutputSize();
-  }
+      if (Section.getOutputAddress()) {
+        LLVM_DEBUG({
+          dbgs() << "BOLT-DEBUG: section " << Section.getName()
+                 << " is already mapped at 0x"
+                 << Twine::utohexstr(Section.getOutputAddress()) << '\n';
+        });
+        continue;
+      }
 
-  // Handling for sections with relocations.
-  for (BinarySection &Section : BC->sections()) {
-    if (!Section.hasSectionRef())
-      continue;
+      if (Section.hasSectionRef()) {
+        LLVM_DEBUG({
+          dbgs() << "BOLT-DEBUG: mapping original section " << Section.getName()
+                 << " to 0x" << Twine::utohexstr(Section.getAddress()) << '\n';
+        });
+        Section.setOutputAddress(Section.getAddress());
+        Section.setOutputFileOffset(Section.getInputFileOffset());
+        RTDyld.reassignSectionAddress(Section.getSectionID(),
+                                      Section.getAddress());
+      } else {
+        NextAvailableAddress =
+            alignTo(NextAvailableAddress, Section.getAlignment());
+        LLVM_DEBUG({
+          dbgs() << "BOLT: mapping section " << Section.getName() << " (0x"
+                 << Twine::utohexstr(Section.getAllocAddress()) << ") to 0x"
+                 << Twine::utohexstr(NextAvailableAddress) << ":0x"
+                 << Twine::utohexstr(NextAvailableAddress +
+                                     Section.getOutputSize())
+                 << '\n';
+        });
 
-    StringRef SectionName = Section.getName();
-    ErrorOr<BinarySection &> OrgSection =
-        BC->getUniqueSectionByName((getOrgSecPrefix() + SectionName).str());
-    if (!OrgSection ||
-        !OrgSection->isAllocatable() ||
-        !OrgSection->isFinalized() ||
-        !OrgSection->hasValidSectionID())
-      continue;
+        RTDyld.reassignSectionAddress(Section.getSectionID(),
+                                      NextAvailableAddress);
+        Section.setOutputAddress(NextAvailableAddress);
+        Section.setOutputFileOffset(
+            getFileOffsetForAddress(NextAvailableAddress));
 
-    if (OrgSection->getOutputAddress()) {
-      LLVM_DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName
-                        << " is already mapped at 0x"
-                        << Twine::utohexstr(OrgSection->getOutputAddress())
-                        << '\n');
-      continue;
+        NextAvailableAddress += Section.getOutputSize();
+      }
     }
-    LLVM_DEBUG(
-        dbgs() << "BOLT: mapping original section " << SectionName << " (0x"
-               << Twine::utohexstr(OrgSection->getAllocAddress()) << ") to 0x"
-               << Twine::utohexstr(Section.getAddress()) << '\n');
-
-    RTDyld.reassignSectionAddress(OrgSection->getSectionID(),
-                                  Section.getAddress());
-
-    OrgSection->setOutputAddress(Section.getAddress());
-    OrgSection->setOutputFileOffset(Section.getContents().data() -
-                                    InputFile->getData().data());
-  }
-}
-
-void RewriteInstance::mapExtraSections(RuntimeDyld &RTDyld) {
-  for (BinarySection &Section : BC->allocatableSections()) {
-    if (Section.getOutputAddress() || !Section.hasValidSectionID())
-      continue;
-    NextAvailableAddress =
-        alignTo(NextAvailableAddress, Section.getAlignment());
-    Section.setOutputAddress(NextAvailableAddress);
-    NextAvailableAddress += Section.getOutputSize();
-
-    LLVM_DEBUG(dbgs() << "BOLT: (extra) mapping " << Section.getName()
-                      << " at 0x" << Twine::utohexstr(Section.getAllocAddress())
-                      << " to 0x"
-                      << Twine::utohexstr(Section.getOutputAddress()) << '\n');
-
-    RTDyld.reassignSectionAddress(Section.getSectionID(),
-                                  Section.getOutputAddress());
-    Section.setOutputFileOffset(
-        getFileOffsetForAddress(Section.getOutputAddress()));
   }
 }
 
@@ -3955,7 +3962,7 @@ void RewriteInstance::patchELFPHDRTable() {
       NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
     } else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
       ErrorOr<BinarySection &> EHFrameHdrSec =
-          BC->getUniqueSectionByName(".eh_frame_hdr");
+          BC->getUniqueSectionByName(getNewSecPrefix() + ".eh_frame_hdr");
       if (EHFrameHdrSec && EHFrameHdrSec->isAllocatable() &&
           EHFrameHdrSec->isFinalized()) {
         NewPhdr.p_offset = EHFrameHdrSec->getOutputFileOffset();
@@ -4026,10 +4033,13 @@ void RewriteInstance::rewriteNoteSections() {
     if (Section.sh_flags & ELF::SHF_ALLOC)
       continue;
 
+    SectionRef SecRef = ELF64LEFile->toSectionRef(&Section);
+    BinarySection *BSec = BC->getSectionForSectionRef(SecRef);
+    assert(BSec && !BSec->isAllocatable() &&
+           "Matching non-allocatable BinarySection should exist.");
+
     StringRef SectionName =
         cantFail(Obj.getSectionName(Section), "cannot get section name");
-    ErrorOr<BinarySection &> BSec = BC->getUniqueSectionByName(SectionName);
-
     if (shouldStrip(Section, SectionName))
       continue;
 
@@ -4046,14 +4056,14 @@ void RewriteInstance::rewriteNoteSections() {
       Size = Section.sh_size;
       StringRef Dataref = InputFile->getData().substr(Section.sh_offset, Size);
       std::string Data;
-      if (BSec && BSec->getPatcher()) {
+      if (BSec->getPatcher()) {
         Data = BSec->getPatcher()->patchBinary(Dataref);
         Dataref = StringRef(Data);
       }
 
       // Section was expanded, so need to treat it as overwrite.
       if (Size != Dataref.size()) {
-        BSec = BC->registerOrUpdateNoteSection(
+        BSec = &BC->registerOrUpdateNoteSection(
             SectionName, copyByteArray(Dataref), Dataref.size());
         Size = 0;
       } else {
@@ -4066,37 +4076,29 @@ void RewriteInstance::rewriteNoteSections() {
     }
 
     // Perform section post-processing.
-    if (BSec && !BSec->isAllocatable()) {
-      assert(BSec->getAlignment() <= Section.sh_addralign &&
-             "alignment exceeds value in file");
-
-      if (BSec->getAllocAddress()) {
-        assert(!DataWritten && "Writing section twice.");
-        (void)DataWritten;
-        SectionData = BSec->getOutputData();
-
-        LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
-                          << " contents to section " << SectionName << '\n');
-        OS.write(reinterpret_cast<char *>(SectionData), BSec->getOutputSize());
-        Size += BSec->getOutputSize();
-      }
-
-      BSec->setOutputFileOffset(NextAvailableOffset);
-      BSec->flushPendingRelocations(OS,
-        [this] (const MCSymbol *S) {
-          return getNewValueForSymbol(S->getName());
-        });
+    assert(BSec->getAlignment() <= Section.sh_addralign &&
+           "alignment exceeds value in file");
+
+    if (BSec->getAllocAddress()) {
+      assert(!DataWritten && "Writing section twice.");
+      (void)DataWritten;
+      SectionData = BSec->getOutputData();
+
+      LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
+                        << " contents to section " << SectionName << '\n');
+      OS.write(reinterpret_cast<char *>(SectionData), BSec->getOutputSize());
+      Size += BSec->getOutputSize();
     }
 
+    BSec->setOutputFileOffset(NextAvailableOffset);
+    BSec->flushPendingRelocations(OS, [this](const MCSymbol *S) {
+      return getNewValueForSymbol(S->getName());
+    });
+
     // Set/modify section info.
-    BinarySection &NewSection =
-      BC->registerOrUpdateNoteSection(SectionName,
-                                      SectionData,
-                                      Size,
-                                      Section.sh_addralign,
-                                      BSec ? BSec->isReadOnly() : false,
-                                      BSec ? BSec->getELFType()
-                                           : ELF::SHT_PROGBITS);
+    BinarySection &NewSection = BC->registerOrUpdateNoteSection(
+        SectionName, SectionData, Size, Section.sh_addralign,
+        BSec->isReadOnly(), BSec->getELFType());
     NewSection.setOutputAddress(0);
     NewSection.setOutputFileOffset(NextAvailableOffset);
 
@@ -4126,22 +4128,10 @@ void RewriteInstance::rewriteNoteSections() {
 
 template <typename ELFT>
 void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
-  using ELFShdrTy = typename ELFT::Shdr;
-  const ELFFile<ELFT> &Obj = File->getELFFile();
-
   // Pre-populate section header string table.
-  for (const ELFShdrTy &Section : cantFail(Obj.sections())) {
-    StringRef SectionName =
-        cantFail(Obj.getSectionName(Section), "cannot get section name");
-    SHStrTab.add(SectionName);
-    std::string OutputSectionName = getOutputSectionName(Obj, Section);
-    if (OutputSectionName != SectionName)
-      SHStrTabPool.emplace_back(std::move(OutputSectionName));
-  }
-  for (const std::string &Str : SHStrTabPool)
-    SHStrTab.add(Str);
   for (const BinarySection &Section : BC->sections())
-    SHStrTab.add(Section.getName());
+    if (!Section.isAnonymous())
+      SHStrTab.add(Section.getOutputName());
   SHStrTab.finalize();
 
   const size_t SHStrTabSize = SHStrTab.getSize();
@@ -4197,21 +4187,6 @@ void RewriteInstance::encodeBATSection() {
                                   /*IsReadOnly=*/true, ELF::SHT_NOTE);
 }
 
-template <typename ELFObjType, typename ELFShdrTy>
-std::string RewriteInstance::getOutputSectionName(const ELFObjType &Obj,
-                                                  const ELFShdrTy &Section) {
-  if (Section.sh_type == ELF::SHT_NULL)
-    return "";
-
-  StringRef SectionName =
-      cantFail(Obj.getSectionName(Section), "cannot get section name");
-
-  if ((Section.sh_flags & ELF::SHF_ALLOC) && willOverwriteSection(SectionName))
-    return (getOrgSecPrefix() + SectionName).str();
-
-  return std::string(SectionName);
-}
-
 template <typename ELFShdrTy>
 bool RewriteInstance::shouldStrip(const ELFShdrTy &Section,
                                   StringRef SectionName) {
@@ -4238,43 +4213,46 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
   const ELFFile<ELFT> &Obj = File->getELFFile();
   typename ELFT::ShdrRange Sections = cantFail(Obj.sections());
 
-  // Keep track of section header entries together with their name.
-  std::vector<std::pair<std::string, ELFShdrTy>> OutputSections;
-  auto addSection = [&](const std::string &Name, const ELFShdrTy &Section) {
+  // Keep track of section header entries attached to the corresponding section.
+  std::vector<std::pair<BinarySection *, ELFShdrTy>> OutputSections;
+  auto addSection = [&](const ELFShdrTy &Section, BinarySection *BinSec) {
     ELFShdrTy NewSection = Section;
-    NewSection.sh_name = SHStrTab.getOffset(Name);
-    OutputSections.emplace_back(Name, std::move(NewSection));
+    NewSection.sh_name = SHStrTab.getOffset(BinSec->getOutputName());
+    OutputSections.emplace_back(BinSec, std::move(NewSection));
   };
 
   // Copy over entries for original allocatable sections using modified name.
   for (const ELFShdrTy &Section : Sections) {
     // Always ignore this section.
     if (Section.sh_type == ELF::SHT_NULL) {
-      OutputSections.emplace_back("", Section);
+      OutputSections.emplace_back(nullptr, Section);
       continue;
     }
 
     if (!(Section.sh_flags & ELF::SHF_ALLOC))
       continue;
 
-    addSection(getOutputSectionName(Obj, Section), Section);
+    SectionRef SecRef = File->toSectionRef(&Section);
+    BinarySection *BinSec = BC->getSectionForSectionRef(SecRef);
+    assert(BinSec && "Matching BinarySection should exist.");
+
+    addSection(Section, BinSec);
   }
 
-  for (const BinarySection &Section : BC->allocatableSections()) {
+  for (BinarySection &Section : BC->allocatableSections()) {
     if (!Section.isFinalized())
       continue;
 
-    if (Section.getName().startswith(getOrgSecPrefix()) ||
-        Section.isAnonymous()) {
+    if (Section.hasSectionRef() || Section.isAnonymous()) {
       if (opts::Verbosity)
         outs() << "BOLT-INFO: not writing section header for section "
-               << Section.getName() << '\n';
+               << Section.getOutputName() << '\n';
       continue;
     }
 
     if (opts::Verbosity >= 1)
-      outs() << "BOLT-INFO: writing section header for " << Section.getName()
-             << '\n';
+      outs() << "BOLT-INFO: writing section header for "
+             << Section.getOutputName() << '\n';
     ELFShdrTy NewSection;
     NewSection.sh_type = ELF::SHT_PROGBITS;
     NewSection.sh_addr = Section.getOutputAddress();
@@ -4285,19 +4263,17 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
     NewSection.sh_link = 0;
     NewSection.sh_info = 0;
     NewSection.sh_addralign = Section.getAlignment();
-    addSection(std::string(Section.getName()), NewSection);
+    addSection(NewSection, &Section);
   }
 
   // Sort all allocatable sections by their offset.
-  llvm::stable_sort(OutputSections,
-                    [](const std::pair<std::string, ELFShdrTy> &A,
-                       const std::pair<std::string, ELFShdrTy> &B) {
-                      return A.second.sh_offset < B.second.sh_offset;
-                    });
+  llvm::stable_sort(OutputSections, [](const auto &A, const auto &B) {
+    return A.second.sh_offset < B.second.sh_offset;
+  });
 
   // Fix section sizes to prevent overlapping.
   ELFShdrTy *PrevSection = nullptr;
-  StringRef PrevSectionName;
+  BinarySection *PrevBinSec = nullptr;
   for (auto &SectionKV : OutputSections) {
     ELFShdrTy &Section = SectionKV.second;
 
@@ -4309,15 +4285,15 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
     if (PrevSection &&
         PrevSection->sh_addr + PrevSection->sh_size > Section.sh_addr) {
       if (opts::Verbosity > 1)
-        outs() << "BOLT-INFO: adjusting size for section " << PrevSectionName
-               << '\n';
+        outs() << "BOLT-INFO: adjusting size for section "
+               << PrevBinSec->getOutputName() << '\n';
       PrevSection->sh_size = Section.sh_addr > PrevSection->sh_addr
                                  ? Section.sh_addr - PrevSection->sh_addr
                                  : 0;
     }
 
     PrevSection = &Section;
-    PrevSectionName = SectionKV.first;
+    PrevBinSec = SectionKV.first;
   }
 
   uint64_t LastFileOffset = 0;
@@ -4336,19 +4312,20 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
     if (shouldStrip(Section, SectionName))
       continue;
 
-    ErrorOr<BinarySection &> BSec = BC->getUniqueSectionByName(SectionName);
-    assert(BSec && "missing section info for non-allocatable section");
+    SectionRef SecRef = File->toSectionRef(&Section);
+    BinarySection *BinSec = BC->getSectionForSectionRef(SecRef);
+    assert(BinSec && "Matching BinarySection should exist.");
 
     ELFShdrTy NewSection = Section;
-    NewSection.sh_offset = BSec->getOutputFileOffset();
-    NewSection.sh_size = BSec->getOutputSize();
+    NewSection.sh_offset = BinSec->getOutputFileOffset();
+    NewSection.sh_size = BinSec->getOutputSize();
 
     if (NewSection.sh_type == ELF::SHT_SYMTAB)
       NewSection.sh_info = NumLocalSymbols;
 
-    addSection(std::string(SectionName), NewSection);
+    addSection(NewSection, BinSec);
 
-    LastFileOffset = BSec->getOutputFileOffset();
+    LastFileOffset = BinSec->getOutputFileOffset();
   }
 
   // Create entries for new non-allocatable sections.
@@ -4357,8 +4334,8 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
       continue;
 
     if (opts::Verbosity >= 1)
-      outs() << "BOLT-INFO: writing section header for " << Section.getName()
-             << '\n';
+      outs() << "BOLT-INFO: writing section header for "
+             << Section.getOutputName() << '\n';
 
     ELFShdrTy NewSection;
     NewSection.sh_type = Section.getELFType();
@@ -4371,18 +4348,13 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
     NewSection.sh_info = 0;
     NewSection.sh_addralign = Section.getAlignment();
 
-    addSection(std::string(Section.getName()), NewSection);
+    addSection(NewSection, &Section);
   }
 
   // Assign indices to sections.
   std::unordered_map<std::string, uint64_t> NameToIndex;
-  for (uint32_t Index = 1; Index < OutputSections.size(); ++Index) {
-    const std::string &SectionName = OutputSections[Index].first;
-    NameToIndex[SectionName] = Index;
-    if (ErrorOr<BinarySection &> Section =
-            BC->getUniqueSectionByName(SectionName))
-      Section->setIndex(Index);
-  }
+  for (uint32_t Index = 1; Index < OutputSections.size(); ++Index)
+    OutputSections[Index].first->setIndex(Index);
 
   // Update section index mapping
   NewSectionIndex.clear();
@@ -4392,20 +4364,21 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
       continue;
 
     size_t OrgIndex = std::distance(Sections.begin(), &Section);
-    std::string SectionName = getOutputSectionName(Obj, Section);
+
+    SectionRef SecRef = File->toSectionRef(&Section);
+    BinarySection *BinSec = BC->getSectionForSectionRef(SecRef);
+    assert(BinSec && "BinarySection should exist for an input section.");
 
     // Some sections are stripped
-    if (!NameToIndex.count(SectionName))
+    if (!BinSec->hasValidIndex())
       continue;
 
-    NewSectionIndex[OrgIndex] = NameToIndex[SectionName];
+    NewSectionIndex[OrgIndex] = BinSec->getIndex();
   }
 
   std::vector<ELFShdrTy> SectionsOnly(OutputSections.size());
   llvm::transform(OutputSections, SectionsOnly.begin(),
-                  [](std::pair<std::string, ELFShdrTy> &SectionInfo) {
-                    return SectionInfo.second;
-                  });
+                  [](auto &SectionInfo) { return SectionInfo.second; });
 
   return SectionsOnly;
 }
@@ -5439,7 +5412,7 @@ void RewriteInstance::rewriteFile() {
     });
 
   // If .eh_frame is present create .eh_frame_hdr.
-  if (EHFrameSection && EHFrameSection->isFinalized())
+  if (EHFrameSection)
     writeEHFrameHeader();
 
   // Add BOLT Addresses Translation maps to allow profile collection to
@@ -5486,25 +5459,33 @@ void RewriteInstance::rewriteFile() {
 }
 
 void RewriteInstance::writeEHFrameHeader() {
+  BinarySection *NewEHFrameSection =
+      getSection(getNewSecPrefix() + getEHFrameSectionName());
+
+  // No need to update the header if no new .eh_frame was created.
+  if (!NewEHFrameSection)
+    return;
+
   DWARFDebugFrame NewEHFrame(BC->TheTriple->getArch(), true,
-                             EHFrameSection->getOutputAddress());
+                             NewEHFrameSection->getOutputAddress());
   Error E = NewEHFrame.parse(DWARFDataExtractor(
-      EHFrameSection->getOutputContents(), BC->AsmInfo->isLittleEndian(),
+      NewEHFrameSection->getOutputContents(), BC->AsmInfo->isLittleEndian(),
       BC->AsmInfo->getCodePointerSize()));
   check_error(std::move(E), "failed to parse EH frame");
 
-  uint64_t OldEHFrameAddress = 0;
-  StringRef OldEHFrameContents;
-  ErrorOr<BinarySection &> OldEHFrameSection =
-      BC->getUniqueSectionByName(Twine(getOrgSecPrefix(), ".eh_frame").str());
-  if (OldEHFrameSection) {
-    OldEHFrameAddress = OldEHFrameSection->getOutputAddress();
-    OldEHFrameContents = OldEHFrameSection->getOutputContents();
-  }
-  DWARFDebugFrame OldEHFrame(BC->TheTriple->getArch(), true, OldEHFrameAddress);
-  Error Er = OldEHFrame.parse(
-      DWARFDataExtractor(OldEHFrameContents, BC->AsmInfo->isLittleEndian(),
-                         BC->AsmInfo->getCodePointerSize()));
+  uint64_t RelocatedEHFrameAddress = 0;
+  StringRef RelocatedEHFrameContents;
+  BinarySection *RelocatedEHFrameSection =
+      getSection(".relocated" + getEHFrameSectionName());
+  if (RelocatedEHFrameSection) {
+    RelocatedEHFrameAddress = RelocatedEHFrameSection->getOutputAddress();
+    RelocatedEHFrameContents = RelocatedEHFrameSection->getOutputContents();
+  }
+  DWARFDebugFrame RelocatedEHFrame(BC->TheTriple->getArch(), true,
+                                   RelocatedEHFrameAddress);
+  Error Er = RelocatedEHFrame.parse(DWARFDataExtractor(
+      RelocatedEHFrameContents, BC->AsmInfo->isLittleEndian(),
+      BC->AsmInfo->getCodePointerSize()));
   check_error(std::move(Er), "failed to parse EH frame");
 
   LLVM_DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n");
@@ -5517,7 +5498,7 @@ void RewriteInstance::writeEHFrameHeader() {
       getFileOffsetForAddress(NextAvailableAddress);
 
   std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
-      OldEHFrame, NewEHFrame, EHFrameHdrOutputAddress, FailedAddresses);
+      RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress, FailedAddresses);
 
   assert(Out->os().tell() == EHFrameHdrFileOffset && "offset mismatch");
   Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size());
@@ -5525,31 +5506,33 @@ void RewriteInstance::writeEHFrameHeader() {
   const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
                                                  /*IsText=*/false,
                                                  /*IsAllocatable=*/true);
+  BinarySection *OldEHFrameHdrSection = getSection(".eh_frame_hdr");
+  if (OldEHFrameHdrSection)
+    OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() + ".eh_frame_hdr");
+
   BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection(
-      ".eh_frame_hdr", ELF::SHT_PROGBITS, Flags, nullptr, NewEHFrameHdr.size(),
-      /*Alignment=*/1);
+      getNewSecPrefix() + ".eh_frame_hdr", ELF::SHT_PROGBITS, Flags, nullptr,
+      NewEHFrameHdr.size(), /*Alignment=*/1);
   EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset);
   EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress);
+  EHFrameHdrSec.setOutputName(".eh_frame_hdr");
 
   NextAvailableAddress += EHFrameHdrSec.getOutputSize();
 
-  // Merge new .eh_frame with original so that gdb can locate all FDEs.
-  if (OldEHFrameSection) {
-    const uint64_t EHFrameSectionSize = (OldEHFrameSection->getOutputAddress() +
-                                         OldEHFrameSection->getOutputSize() -
-                                         EHFrameSection->getOutputAddress());
-    EHFrameSection =
-      BC->registerOrUpdateSection(".eh_frame",
-                                  EHFrameSection->getELFType(),
-                                  EHFrameSection->getELFFlags(),
-                                  EHFrameSection->getOutputData(),
-                                  EHFrameSectionSize,
-                                  EHFrameSection->getAlignment());
-    BC->deregisterSection(*OldEHFrameSection);
+  // Merge new .eh_frame with the relocated original so that gdb can locate all
+  // FDEs.
+  if (RelocatedEHFrameSection) {
+    const uint64_t NewEHFrameSectionSize =
+        RelocatedEHFrameSection->getOutputAddress() +
+        RelocatedEHFrameSection->getOutputSize() -
+        NewEHFrameSection->getOutputAddress();
+    NewEHFrameSection->updateContents(NewEHFrameSection->getOutputData(),
+                                      NewEHFrameSectionSize);
+    BC->deregisterSection(*RelocatedEHFrameSection);
   }
 
   LLVM_DEBUG(dbgs() << "BOLT-DEBUG: size of .eh_frame after merge is "
-                    << EHFrameSection->getOutputSize() << '\n');
+                    << NewEHFrameSection->getOutputSize() << '\n');
 }
 
 uint64_t RewriteInstance::getNewValueForSymbol(const StringRef Name) {
index f8ea863..7e6a75a 100644 (file)
@@ -23,8 +23,6 @@
 # one it just created.
 
 # REQUIRES: system-linux
-# Currently XFAIL as we do not support it.
-# XFAIL: *
 
 # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux \
 # RUN:   %s -o %t.o