mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[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:
@@ -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 ®isterSection(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 ®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 @@ 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())
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user