diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -179,6 +179,10 @@ using NameToSectionMapType = std::multimap; NameToSectionMapType NameToSection; + /// Map section references to BinarySection for matching sections in the + /// input file to internal section representation. + DenseMap SectionRefToBinarySection; + /// Low level section registration. BinarySection ®isterSection(BinarySection *Section); @@ -224,6 +228,9 @@ /// DWARF line info for CUs. std::map DwarfLineTablesCUMap; + /// Internal helper for removing section name from a lookup table. + void deregisterSectionName(const BinarySection &Section); + public: static Expected> createBinaryContext(const ObjectFile *File, bool IsPIC, @@ -951,13 +958,13 @@ BinarySection ®isterSection(SectionRef Section); /// Register a copy of /p OriginalSection under a different name. - BinarySection ®isterSection(StringRef SectionName, + BinarySection ®isterSection(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 ®isterOrUpdateSection(StringRef Name, unsigned ELFType, + BinarySection ®isterOrUpdateSection(const Twine &Name, unsigned ELFType, unsigned ELFFlags, uint8_t *Data = nullptr, uint64_t Size = 0, @@ -967,7 +974,7 @@ /// 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 @@ 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 sections() { auto notNull = [](const SectionIterator &Itr) { return (bool)*Itr; }; @@ -1073,20 +1086,26 @@ return const_cast(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 - 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 - 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 getUniqueSectionByName(StringRef SectionName) const { + ErrorOr + getUniqueSectionByName(const Twine &SectionName) const { auto Sections = getSectionByName(SectionName); if (Sections.begin() != Sections.end() && std::next(Sections.begin()) == Sections.end()) diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h --- a/bolt/include/bolt/Core/BinarySection.h +++ b/bolt/include/bolt/Core/BinarySection.h @@ -48,7 +48,7 @@ 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 @@ 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 @@ } // 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(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 @@ 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 @@ return SectionID; } bool hasValidSectionID() const { return SectionID != -1u; } + bool hasValidIndex() { return Index != 0; } uint32_t getIndex() const { return Index; } // mutation @@ -445,12 +447,12 @@ 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; @@ -459,6 +461,13 @@ 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(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. diff --git a/bolt/include/bolt/Rewrite/ExecutableFileMemoryManager.h b/bolt/include/bolt/Rewrite/ExecutableFileMemoryManager.h --- a/bolt/include/bolt/Rewrite/ExecutableFileMemoryManager.h +++ b/bolt/include/bolt/Rewrite/ExecutableFileMemoryManager.h @@ -35,6 +35,12 @@ }; SmallVector 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 @@ 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 diff --git a/bolt/include/bolt/Rewrite/MachORewriteInstance.h b/bolt/include/bolt/Rewrite/MachORewriteInstance.h --- a/bolt/include/bolt/Rewrite/MachORewriteInstance.h +++ b/bolt/include/bolt/Rewrite/MachORewriteInstance.h @@ -46,6 +46,7 @@ void processProfileDataPreCFG(); void processProfileData(); + static StringRef getNewSecPrefix() { return ".bolt.new"; } static StringRef getOrgSecPrefix() { return ".bolt.org"; } void mapInstrumentationSection(StringRef SectionName); diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -169,6 +169,8 @@ void postProcessFunctions(); + void preregisterSections(); + /// Run optimizations that operate at the binary, or post-linker, level. void runOptimizationPasses(); @@ -199,10 +201,13 @@ std::vector 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 @@ /// 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 - 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 @@ -419,6 +419,11 @@ /// 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 @@ /// 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 @@ /// Contains information about pseudo probe details, like its address ErrorOr PseudoProbeSection{std::errc::bad_address}; + /// Helper for accessing sections by name. + BinarySection *getSection(const Twine &Name) { + ErrorOr 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 @@ /// Section header string table. StringTableBuilder SHStrTab; - std::vector SHStrTabPool; /// A rewrite of strtab std::string NewStrTab; diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1932,6 +1932,10 @@ 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(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 @@ 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 AbsSection = getUniqueSectionByName(""); + 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 @@ ++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 @@ 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"; diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp --- a/bolt/lib/Core/BinaryEmitter.cpp +++ b/bolt/lib/Core/BinaryEmitter.cpp @@ -801,11 +801,12 @@ 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::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(); } } diff --git a/bolt/lib/Core/BinarySection.cpp b/bolt/lib/Core/BinarySection.cpp --- a/bolt/lib/Core/BinarySection.cpp +++ b/bolt/lib/Core/BinarySection.cpp @@ -67,8 +67,8 @@ 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()); diff --git a/bolt/lib/Passes/ReorderData.cpp b/bolt/lib/Passes/ReorderData.cpp --- a/bolt/lib/Passes/ReorderData.cpp +++ b/bolt/lib/Passes/ReorderData.cpp @@ -500,19 +500,21 @@ << Section->getName() << " falling back to splitting " << "instead of in-place reordering.\n"; - // Copy original section to
.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 &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 { diff --git a/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp b/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp --- a/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp +++ b/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp @@ -55,19 +55,50 @@ } } - 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 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 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; } diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp --- a/bolt/lib/Rewrite/MachORewriteInstance.cpp +++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp @@ -508,6 +508,8 @@ static_cast(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); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -412,6 +412,8 @@ // 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(InputFile); const ELFFile &Obj = ELF64LEFile->getELFFile(); @@ -751,6 +753,8 @@ if (opts::DiffOnly) return Error::success(); + preregisterSections(); + runOptimizationPasses(); emitAndLink(); @@ -1505,8 +1509,12 @@ } 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 @@ // 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 @@ 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 @@ } // 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 @@ exit(1); } + ErrorOr TextSection = + BC->getUniqueSectionByName(BC->getMainCodeSectionName()); + if (BC->HasRelocations && TextSection) + BC->renameSection(*TextSection, getOrgSecPrefix() + ".text"); + ////////////////////////////////////////////////////////////////////////////// // Assign addresses to new sections. ////////////////////////////////////////////////////////////////////////////// @@ -3175,7 +3205,8 @@ 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::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 RewriteInstance::getCodeSections() { @@ -3722,7 +3773,7 @@ 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 @@ 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::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 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 OldEHFrameSection = - BC->getUniqueSectionByName(Twine(getOrgSecPrefix(), ".eh_frame").str()); - if (OldEHFrameSection) { - RTDyld.reassignSectionAddress(OldEHFrameSection->getSectionID(), - NextAvailableAddress); - BC->deregisterSection(*OldEHFrameSection); - } - } - - for (std::string &SectionName : Sections) { - ErrorOr 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 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 @@ NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum; } else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { ErrorOr 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 @@ 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 BSec = BC->getUniqueSectionByName(SectionName); - if (shouldStrip(Section, SectionName)) continue; @@ -4046,14 +4056,14 @@ 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 @@ } // 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(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(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 @@ template void RewriteInstance::finalizeSectionStringTable(ELFObjectFile *File) { - using ELFShdrTy = typename ELFT::Shdr; - const ELFFile &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 @@ /*IsReadOnly=*/true, ELF::SHT_NOTE); } -template -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 bool RewriteInstance::shouldStrip(const ELFShdrTy &Section, StringRef SectionName) { @@ -4238,43 +4213,46 @@ const ELFFile &Obj = File->getELFFile(); typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); - // Keep track of section header entries together with their name. - std::vector> OutputSections; - auto addSection = [&](const std::string &Name, const ELFShdrTy &Section) { + // Keep track of section header entries attached to the corresponding section. + std::vector> 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 @@ 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 &A, - const std::pair &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 @@ 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 @@ if (shouldStrip(Section, SectionName)) continue; - ErrorOr 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 @@ 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 @@ 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 NameToIndex; - for (uint32_t Index = 1; Index < OutputSections.size(); ++Index) { - const std::string &SectionName = OutputSections[Index].first; - NameToIndex[SectionName] = Index; - if (ErrorOr 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 @@ 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 SectionsOnly(OutputSections.size()); llvm::transform(OutputSections, SectionsOnly.begin(), - [](std::pair &SectionInfo) { - return SectionInfo.second; - }); + [](auto &SectionInfo) { return SectionInfo.second; }); return SectionsOnly; } @@ -5439,7 +5412,7 @@ }); // 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::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 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 @@ getFileOffsetForAddress(NextAvailableAddress); std::vector 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 @@ 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) { diff --git a/bolt/test/X86/dynrelocs.s b/bolt/test/X86/dynrelocs.s --- a/bolt/test/X86/dynrelocs.s +++ b/bolt/test/X86/dynrelocs.s @@ -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