[BOLT] Section-handling refactoring/overhaul

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
This commit is contained in:
Maksim Panchenko
2022-09-22 12:05:12 -07:00
parent d383adec4d
commit 4d3a0cade2
13 changed files with 433 additions and 326 deletions

View 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())

View 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.

View 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

View 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);

View 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;

View 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";

View 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();
}
}

View 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());

View 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 {

View 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");
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);
LLVM_DEBUG(
dbgs() << "BOLT: allocating "
<< (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
<< " section : " << SectionName << " with size " << Size
<< ", alignment " << Alignment << " at " << Ret
<< ", ID = " << SectionID << "\n");
return Ret;
}

View 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);

View 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,102 +3840,57 @@ 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);
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;
if (!EHFrameSection || !EHFrameSection->isFinalized()) {
ErrorOr<BinarySection &> OldEHFrameSection =
BC->getUniqueSectionByName(Twine(getOrgSecPrefix(), ".eh_frame").str());
if (OldEHFrameSection) {
RTDyld.reassignSectionAddress(OldEHFrameSection->getSectionID(),
NextAvailableAddress);
BC->deregisterSection(*OldEHFrameSection);
if (Section.isReadOnly() != (SType == ST_READONLY))
continue;
if (Section.getOutputAddress()) {
LLVM_DEBUG({
dbgs() << "BOLT-DEBUG: section " << Section.getName()
<< " is already mapped at 0x"
<< Twine::utohexstr(Section.getOutputAddress()) << '\n';
});
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';
});
RTDyld.reassignSectionAddress(Section.getSectionID(),
NextAvailableAddress);
Section.setOutputAddress(NextAvailableAddress);
Section.setOutputFileOffset(
getFileOffsetForAddress(NextAvailableAddress));
NextAvailableAddress += Section.getOutputSize();
}
}
}
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');
RTDyld.reassignSectionAddress(Section->getSectionID(),
NextAvailableAddress);
Section->setOutputAddress(NextAvailableAddress);
Section->setOutputFileOffset(getFileOffsetForAddress(NextAvailableAddress));
NextAvailableAddress += Section->getOutputSize();
}
// Handling for sections with relocations.
for (BinarySection &Section : BC->sections()) {
if (!Section.hasSectionRef())
continue;
StringRef SectionName = Section.getName();
ErrorOr<BinarySection &> OrgSection =
BC->getUniqueSectionByName((getOrgSecPrefix() + SectionName).str());
if (!OrgSection ||
!OrgSection->isAllocatable() ||
!OrgSection->isFinalized() ||
!OrgSection->hasValidSectionID())
continue;
if (OrgSection->getOutputAddress()) {
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName
<< " is already mapped at 0x"
<< Twine::utohexstr(OrgSection->getOutputAddress())
<< '\n');
continue;
}
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()));
}
}
void RewriteInstance::updateOutputValues(const MCAsmLayout &Layout) {
@@ -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");
assert(BSec->getAlignment() <= Section.sh_addralign &&
"alignment exceeds value in file");
if (BSec->getAllocAddress()) {
assert(!DataWritten && "Writing section twice.");
(void)DataWritten;
SectionData = BSec->getOutputData();
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());
});
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();
uint64_t RelocatedEHFrameAddress = 0;
StringRef RelocatedEHFrameContents;
BinarySection *RelocatedEHFrameSection =
getSection(".relocated" + getEHFrameSectionName());
if (RelocatedEHFrameSection) {
RelocatedEHFrameAddress = RelocatedEHFrameSection->getOutputAddress();
RelocatedEHFrameContents = RelocatedEHFrameSection->getOutputContents();
}
DWARFDebugFrame OldEHFrame(BC->TheTriple->getArch(), true, OldEHFrameAddress);
Error Er = OldEHFrame.parse(
DWARFDataExtractor(OldEHFrameContents, BC->AsmInfo->isLittleEndian(),
BC->AsmInfo->getCodePointerSize()));
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) {

View 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