forked from OSchip/llvm-project
[BOLT] Refactoring of section handling code
Summary: This is a big refactoring of the section handling code. I've removed the SectionInfoMap and NoteSectionInfo and stored all the associated info about sections in BinaryContext and BinarySection classes. BinarySections should now hold all the info we care about for each section. They can be initialized from SectionRefs but don't necessarily require one to be created. There are only one or two spots that needed access to the original SectionRef to work properly. The trickiest part was making sure RewriteInstance.cpp iterated over the proper sets of sections for each of it's different types of processing. The different sets are broken down roughly as allocatable and non-alloctable and "registered" (I couldn't think up a better name). "Registered" means that the section has been updated to include output information, i.e. contents, file offset/address, new size, etc. It may help to have special iterators on BinaryContext to iterate over the different classes to make things easier. I can do that if you guys think it is worthwhile. I found pointee_iterator in the llvm ADT code. Use that for iterating over BBs in BinaryFunction rather than the custom iterator class. (cherry picked from FBD6879086)
This commit is contained in:
parent
6744f0dbeb
commit
ddefc770b0
|
@ -23,6 +23,9 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace bolt;
|
using namespace bolt;
|
||||||
|
|
||||||
|
#undef DEBUG_TYPE
|
||||||
|
#define DEBUG_TYPE "bolt"
|
||||||
|
|
||||||
namespace opts {
|
namespace opts {
|
||||||
|
|
||||||
extern cl::OptionCategory BoltCategory;
|
extern cl::OptionCategory BoltCategory;
|
||||||
|
@ -31,23 +34,30 @@ static cl::opt<bool>
|
||||||
PrintDebugInfo("print-debug-info",
|
PrintDebugInfo("print-debug-info",
|
||||||
cl::desc("print debug info when printing functions"),
|
cl::desc("print debug info when printing functions"),
|
||||||
cl::Hidden,
|
cl::Hidden,
|
||||||
|
cl::ZeroOrMore,
|
||||||
cl::cat(BoltCategory));
|
cl::cat(BoltCategory));
|
||||||
|
|
||||||
static cl::opt<bool>
|
cl::opt<bool>
|
||||||
PrintRelocations("print-relocations",
|
PrintRelocations("print-relocations",
|
||||||
cl::desc("print relocations when printing functions"),
|
cl::desc("print relocations when printing functions/objects"),
|
||||||
cl::Hidden,
|
cl::Hidden,
|
||||||
|
cl::ZeroOrMore,
|
||||||
cl::cat(BoltCategory));
|
cl::cat(BoltCategory));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
PrintMemData("print-mem-data",
|
PrintMemData("print-mem-data",
|
||||||
cl::desc("print memory data annotations when printing functions"),
|
cl::desc("print memory data annotations when printing functions"),
|
||||||
cl::Hidden,
|
cl::Hidden,
|
||||||
|
cl::ZeroOrMore,
|
||||||
cl::cat(BoltCategory));
|
cl::cat(BoltCategory));
|
||||||
|
|
||||||
} // namespace opts
|
} // namespace opts
|
||||||
|
|
||||||
BinaryContext::~BinaryContext() { }
|
BinaryContext::~BinaryContext() {
|
||||||
|
for (auto *Section : Sections) {
|
||||||
|
delete Section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<MCObjectWriter>
|
std::unique_ptr<MCObjectWriter>
|
||||||
BinaryContext::createObjectWriter(raw_pwrite_stream &OS) {
|
BinaryContext::createObjectWriter(raw_pwrite_stream &OS) {
|
||||||
|
@ -474,20 +484,82 @@ BinaryContext::getSectionForAddress(uint64_t Address) const {
|
||||||
return std::make_error_code(std::errc::bad_address);
|
return std::make_error_code(std::errc::bad_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
BinarySection &BinaryContext::registerSection(SectionRef Section) {
|
BinarySection &BinaryContext::registerSection(BinarySection *Section) {
|
||||||
StringRef Name;
|
assert(!Section->getName().empty() &&
|
||||||
Section.getName(Name);
|
"can't register sections without a name");
|
||||||
auto Res = Sections.insert(BinarySection(Section));
|
auto Res = Sections.insert(Section);
|
||||||
assert(Res.second && "can't register the same section twice.");
|
assert(Res.second && "can't register the same section twice.");
|
||||||
// Cast away const here because std::set always stores values by
|
|
||||||
// const. It's ok to do this because we can never change the
|
|
||||||
// BinarySection properties that affect set ordering.
|
|
||||||
auto *BS = const_cast<BinarySection *>(&*Res.first);
|
|
||||||
// Only register sections with addresses in the AddressToSection map.
|
// Only register sections with addresses in the AddressToSection map.
|
||||||
if (Section.getAddress())
|
if (Section->getAddress())
|
||||||
AddressToSection.insert(std::make_pair(Section.getAddress(), BS));
|
AddressToSection.insert(std::make_pair(Section->getAddress(), Section));
|
||||||
NameToSection.insert(std::make_pair(Name, BS));
|
NameToSection.insert(std::make_pair(Section->getName(), Section));
|
||||||
return *BS;
|
DEBUG(dbgs() << "BOLT-DEBUG: registering " << *Section << "\n");
|
||||||
|
return *Section;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinarySection &BinaryContext::registerSection(SectionRef Section) {
|
||||||
|
return registerSection(new BinarySection(Section));
|
||||||
|
}
|
||||||
|
|
||||||
|
BinarySection &BinaryContext::registerOrUpdateSection(StringRef Name,
|
||||||
|
unsigned ELFType,
|
||||||
|
unsigned ELFFlags,
|
||||||
|
uint8_t *Data,
|
||||||
|
uint64_t Size,
|
||||||
|
unsigned Alignment,
|
||||||
|
bool IsLocal) {
|
||||||
|
auto NamedSections = getSectionByName(Name);
|
||||||
|
if (NamedSections.begin() != NamedSections.end()) {
|
||||||
|
assert(std::next(NamedSections.begin()) == NamedSections.end() &&
|
||||||
|
"can only update unique sections");
|
||||||
|
auto *Section = NamedSections.begin()->second;
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "BOLT-DEBUG: updating " << *Section << " -> ");
|
||||||
|
const auto Flag = Section->isAllocatable();
|
||||||
|
Section->update(Data, Size, Alignment, ELFType, ELFFlags, IsLocal);
|
||||||
|
DEBUG(dbgs() << *Section << "\n");
|
||||||
|
assert(Flag == Section->isAllocatable() &&
|
||||||
|
"can't change section allocation status");
|
||||||
|
return *Section;
|
||||||
|
}
|
||||||
|
|
||||||
|
return registerSection(new BinarySection(Name, Data, Size, Alignment,
|
||||||
|
ELFType, ELFFlags, IsLocal));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BinaryContext::deregisterSection(BinarySection &Section) {
|
||||||
|
auto *SectionPtr = &Section;
|
||||||
|
auto Itr = Sections.find(SectionPtr);
|
||||||
|
if (Itr != Sections.end()) {
|
||||||
|
auto Range = AddressToSection.equal_range(SectionPtr->getAddress());
|
||||||
|
while (Range.first != Range.second) {
|
||||||
|
if (Range.first->second == SectionPtr) {
|
||||||
|
AddressToSection.erase(Range.first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++Range.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NameRange = NameToSection.equal_range(SectionPtr->getName());
|
||||||
|
while (NameRange.first != NameRange.second) {
|
||||||
|
if (NameRange.first->second == SectionPtr) {
|
||||||
|
NameToSection.erase(NameRange.first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++NameRange.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sections.erase(Itr);
|
||||||
|
delete SectionPtr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinaryContext::printSections(raw_ostream &OS) const {
|
||||||
|
for (auto &Section : Sections) {
|
||||||
|
OS << "BOLT-INFO: " << *Section << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<uint64_t>
|
ErrorOr<uint64_t>
|
||||||
|
@ -504,27 +576,24 @@ BinaryContext::extractPointerAtAddress(uint64_t Address) const {
|
||||||
return DE.getAddress(&SectionOffset);
|
return DE.getAddress(&SectionOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryContext::addSectionRelocation(BinarySection &Section,
|
|
||||||
uint64_t Offset,
|
|
||||||
MCSymbol *Symbol,
|
|
||||||
uint64_t Type,
|
|
||||||
uint64_t Addend) {
|
|
||||||
Section.addRelocation(Offset, Symbol, Type, Addend);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinaryContext::addRelocation(uint64_t Address,
|
void BinaryContext::addRelocation(uint64_t Address,
|
||||||
MCSymbol *Symbol,
|
MCSymbol *Symbol,
|
||||||
uint64_t Type,
|
uint64_t Type,
|
||||||
uint64_t Addend) {
|
uint64_t Addend,
|
||||||
|
uint64_t Value) {
|
||||||
auto Section = getSectionForAddress(Address);
|
auto Section = getSectionForAddress(Address);
|
||||||
assert(Section && "cannot find section for address");
|
assert(Section && "cannot find section for address");
|
||||||
Section->addRelocation(Address - Section->getAddress(), Symbol, Type, Addend);
|
Section->addRelocation(Address - Section->getAddress(),
|
||||||
|
Symbol,
|
||||||
|
Type,
|
||||||
|
Addend,
|
||||||
|
Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryContext::removeRelocationAt(uint64_t Address) {
|
bool BinaryContext::removeRelocationAt(uint64_t Address) {
|
||||||
auto Section = getSectionForAddress(Address);
|
auto Section = getSectionForAddress(Address);
|
||||||
assert(Section && "cannot find section for address");
|
assert(Section && "cannot find section for address");
|
||||||
Section->removeRelocationAt(Address - Section->getAddress());
|
return Section->removeRelocationAt(Address - Section->getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Relocation *BinaryContext::getRelocationAt(uint64_t Address) {
|
const Relocation *BinaryContext::getRelocationAt(uint64_t Address) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "BinarySection.h"
|
#include "BinarySection.h"
|
||||||
#include "DebugData.h"
|
#include "DebugData.h"
|
||||||
|
#include "llvm/ADT/iterator.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
|
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
|
@ -58,9 +59,17 @@ class BinaryContext {
|
||||||
BinaryContext() = delete;
|
BinaryContext() = delete;
|
||||||
|
|
||||||
/// Set of all sections.
|
/// Set of all sections.
|
||||||
using SectionSetType = std::set<BinarySection>;
|
struct CompareSections {
|
||||||
|
bool operator()(const BinarySection *A, const BinarySection *B) const {
|
||||||
|
return *A < *B;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using SectionSetType = std::set<BinarySection *, CompareSections>;
|
||||||
SectionSetType Sections;
|
SectionSetType Sections;
|
||||||
|
|
||||||
|
using SectionIterator = pointee_iterator<SectionSetType::iterator>;
|
||||||
|
using SectionConstIterator = pointee_iterator<SectionSetType::const_iterator>;
|
||||||
|
|
||||||
/// Map virtual address to a section. It is possible to have more than one
|
/// Map virtual address to a section. It is possible to have more than one
|
||||||
/// section mapped to the same address, e.g. non-allocatable sections.
|
/// section mapped to the same address, e.g. non-allocatable sections.
|
||||||
using AddressToSectionMapType = std::multimap<uint64_t, BinarySection *>;
|
using AddressToSectionMapType = std::multimap<uint64_t, BinarySection *>;
|
||||||
|
@ -70,6 +79,9 @@ class BinaryContext {
|
||||||
/// have multiple sections with the same name.
|
/// have multiple sections with the same name.
|
||||||
using NameToSectionMapType = std::multimap<std::string, BinarySection *>;
|
using NameToSectionMapType = std::multimap<std::string, BinarySection *>;
|
||||||
NameToSectionMapType NameToSection;
|
NameToSectionMapType NameToSection;
|
||||||
|
|
||||||
|
/// Low level section registration.
|
||||||
|
BinarySection ®isterSection(BinarySection *Section);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// [name] -> [address] map used for global symbol resolution.
|
/// [name] -> [address] map used for global symbol resolution.
|
||||||
|
@ -125,8 +137,6 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<MCAsmBackend> MAB;
|
std::unique_ptr<MCAsmBackend> MAB;
|
||||||
|
|
||||||
std::function<void(std::error_code)> ErrorCheck;
|
|
||||||
|
|
||||||
DataReader &DR;
|
DataReader &DR;
|
||||||
|
|
||||||
/// Indicates if relocations are availabe for usage.
|
/// Indicates if relocations are availabe for usage.
|
||||||
|
@ -224,18 +234,53 @@ public:
|
||||||
ErrorOr<ArrayRef<uint8_t>>
|
ErrorOr<ArrayRef<uint8_t>>
|
||||||
getFunctionData(const BinaryFunction &Function) const;
|
getFunctionData(const BinaryFunction &Function) const;
|
||||||
|
|
||||||
/// Register information about the given section so we can look up
|
/// Register information about the given \p Section so we can look up
|
||||||
/// sections for addresses.
|
/// sections by address.
|
||||||
BinarySection ®isterSection(SectionRef Section);
|
BinarySection ®isterSection(SectionRef Section);
|
||||||
|
|
||||||
iterator_range<SectionSetType::iterator> sections() {
|
/// 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,
|
||||||
|
unsigned ELFFlags,
|
||||||
|
uint8_t *Data = nullptr,
|
||||||
|
uint64_t Size = 0,
|
||||||
|
unsigned Alignment = 1,
|
||||||
|
bool IsLocal = false);
|
||||||
|
|
||||||
|
/// Register the information for the note (non-allocatable) section
|
||||||
|
/// with the given /p Name. If the section already exists, the
|
||||||
|
/// information in the section will be updated with the new data.
|
||||||
|
BinarySection ®isterOrUpdateNoteSection(StringRef Name,
|
||||||
|
uint8_t *Data = nullptr,
|
||||||
|
uint64_t Size = 0,
|
||||||
|
unsigned Alignment = 1,
|
||||||
|
bool IsReadOnly = true,
|
||||||
|
unsigned ELFType = ELF::SHT_PROGBITS,
|
||||||
|
bool IsLocal = false) {
|
||||||
|
return registerOrUpdateSection(Name, ELFType,
|
||||||
|
BinarySection::getFlags(IsReadOnly),
|
||||||
|
Data, Size, Alignment, IsLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
/// Iterate over all registered sections.
|
||||||
|
iterator_range<SectionIterator> sections() {
|
||||||
return make_range(Sections.begin(), Sections.end());
|
return make_range(Sections.begin(), Sections.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator_range<SectionSetType::const_iterator> sections() const {
|
/// Iterate over all registered sections.
|
||||||
|
iterator_range<SectionConstIterator> sections() const {
|
||||||
return make_range(Sections.begin(), Sections.end());
|
return make_range(Sections.begin(), Sections.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Print all sections.
|
||||||
|
void printSections(raw_ostream& OS) const;
|
||||||
|
|
||||||
/// Return largest section containing the given \p Address. These
|
/// Return largest section containing the given \p Address. These
|
||||||
/// functions only work for allocatable sections, i.e. ones with non-zero
|
/// functions only work for allocatable sections, i.e. ones with non-zero
|
||||||
/// addresses.
|
/// addresses.
|
||||||
|
@ -305,17 +350,12 @@ public:
|
||||||
BinaryFunction &ParentBF,
|
BinaryFunction &ParentBF,
|
||||||
std::map<uint64_t, BinaryFunction> &BFs);
|
std::map<uint64_t, BinaryFunction> &BFs);
|
||||||
|
|
||||||
/// Add relocation for \p Section at a given \p Offset.
|
/// Add a Section relocation at a given \p Address.
|
||||||
void addSectionRelocation(BinarySection &Section, uint64_t Offset,
|
|
||||||
MCSymbol *Symbol, uint64_t Type,
|
|
||||||
uint64_t Addend = 0);
|
|
||||||
|
|
||||||
/// Add a relocation at a given \p Address.
|
|
||||||
void addRelocation(uint64_t Address, MCSymbol *Symbol, uint64_t Type,
|
void addRelocation(uint64_t Address, MCSymbol *Symbol, uint64_t Type,
|
||||||
uint64_t Addend = 0);
|
uint64_t Addend = 0, uint64_t Value = 0);
|
||||||
|
|
||||||
/// Remove registered relocation at a given \p Address.
|
/// Remove registered relocation at a given \p Address.
|
||||||
void removeRelocationAt(uint64_t Address);
|
bool removeRelocationAt(uint64_t Address);
|
||||||
|
|
||||||
/// Return a relocation registered at a given \p Address, or nullptr if there
|
/// Return a relocation registered at a given \p Address, or nullptr if there
|
||||||
/// is no relocation at such address.
|
/// is no relocation at such address.
|
||||||
|
|
|
@ -1312,8 +1312,18 @@ void BinaryFunction::postProcessJumpTables() {
|
||||||
TakenBranches.emplace_back(JTSiteOffset, TargetOffset);
|
TakenBranches.emplace_back(JTSiteOffset, TargetOffset);
|
||||||
|
|
||||||
// Take ownership of jump table relocations.
|
// Take ownership of jump table relocations.
|
||||||
if (BC.HasRelocations)
|
if (BC.HasRelocations) {
|
||||||
BC.removeRelocationAt(JT->Address + EntryOffset);
|
auto EntryAddress = JT->Address + EntryOffset;
|
||||||
|
auto Res = BC.removeRelocationAt(EntryAddress);
|
||||||
|
(void)Res;
|
||||||
|
DEBUG(
|
||||||
|
auto Section = BC.getSectionForAddress(EntryAddress);
|
||||||
|
auto Offset = EntryAddress - Section->getAddress();
|
||||||
|
dbgs() << "BOLT-DEBUG: removing relocation from section "
|
||||||
|
<< Section->getName() << " at offset 0x"
|
||||||
|
<< Twine::utohexstr(Offset) << " = "
|
||||||
|
<< Res << '\n');
|
||||||
|
}
|
||||||
|
|
||||||
EntryOffset += JT->EntrySize;
|
EntryOffset += JT->EntrySize;
|
||||||
|
|
||||||
|
@ -3363,7 +3373,7 @@ void BinaryFunction::JumpTable::updateOriginal(BinaryContext &BC) {
|
||||||
<< " at offset " << Twine::utohexstr(Offset) << " for symbol "
|
<< " at offset " << Twine::utohexstr(Offset) << " for symbol "
|
||||||
<< Entry->getName() << " with addend "
|
<< Entry->getName() << " with addend "
|
||||||
<< Twine::utohexstr(RelAddend) << '\n');
|
<< Twine::utohexstr(RelAddend) << '\n');
|
||||||
BC.addSectionRelocation(*Section, Offset, Entry, RelType, RelAddend);
|
Section->addRelocation(Offset, Entry, RelType, RelAddend);
|
||||||
Offset += EntrySize;
|
Offset += EntrySize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "DebugData.h"
|
#include "DebugData.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ADT/ilist.h"
|
#include "llvm/ADT/ilist.h"
|
||||||
|
#include "llvm/ADT/iterator.h"
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
#include "llvm/BinaryFormat/Dwarf.h"
|
||||||
#include "llvm/MC/MCCodeEmitter.h"
|
#include "llvm/MC/MCCodeEmitter.h"
|
||||||
#include "llvm/MC/MCContext.h"
|
#include "llvm/MC/MCContext.h"
|
||||||
|
@ -600,7 +601,7 @@ public:
|
||||||
std::map<unsigned, MCSymbol *> Labels;
|
std::map<unsigned, MCSymbol *> Labels;
|
||||||
|
|
||||||
/// Corresponding section if any.
|
/// Corresponding section if any.
|
||||||
SectionInfo *SecInfo{nullptr};
|
ErrorOr<BinarySection &> Section{std::errc::bad_address};
|
||||||
|
|
||||||
/// Corresponding section name if any.
|
/// Corresponding section name if any.
|
||||||
std::string SectionName;
|
std::string SectionName;
|
||||||
|
@ -747,21 +748,6 @@ private:
|
||||||
/// Count the number of functions created.
|
/// Count the number of functions created.
|
||||||
static uint64_t Count;
|
static uint64_t Count;
|
||||||
|
|
||||||
template <typename Itr, typename T>
|
|
||||||
class Iterator : public std::iterator<std::bidirectional_iterator_tag, T> {
|
|
||||||
public:
|
|
||||||
Iterator &operator++() { ++itr; return *this; }
|
|
||||||
Iterator &operator--() { --itr; return *this; }
|
|
||||||
Iterator operator++(int) { auto tmp(itr); itr++; return tmp; }
|
|
||||||
Iterator operator--(int) { auto tmp(itr); itr--; return tmp; }
|
|
||||||
bool operator==(const Iterator& other) const { return itr == other.itr; }
|
|
||||||
bool operator!=(const Iterator& other) const { return itr != other.itr; }
|
|
||||||
T& operator*() { return **itr; }
|
|
||||||
Iterator(Itr itr) : itr(itr) { }
|
|
||||||
private:
|
|
||||||
Itr itr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Register alternative function name.
|
/// Register alternative function name.
|
||||||
void addAlternativeName(std::string NewName) {
|
void addAlternativeName(std::string NewName) {
|
||||||
Names.emplace_back(NewName);
|
Names.emplace_back(NewName);
|
||||||
|
@ -842,13 +828,12 @@ public:
|
||||||
|
|
||||||
BinaryFunction(BinaryFunction &&) = default;
|
BinaryFunction(BinaryFunction &&) = default;
|
||||||
|
|
||||||
typedef Iterator<BasicBlockListType::iterator, BinaryBasicBlock> iterator;
|
using iterator = pointee_iterator<BasicBlockListType::iterator>;
|
||||||
typedef Iterator<BasicBlockListType::const_iterator,
|
using const_iterator = pointee_iterator<BasicBlockListType::const_iterator>;
|
||||||
const BinaryBasicBlock> const_iterator;
|
using reverse_iterator =
|
||||||
typedef Iterator<BasicBlockListType::reverse_iterator,
|
pointee_iterator<BasicBlockListType::reverse_iterator>;
|
||||||
BinaryBasicBlock> reverse_iterator;
|
using const_reverse_iterator =
|
||||||
typedef Iterator<BasicBlockListType::const_reverse_iterator,
|
pointee_iterator<BasicBlockListType::const_reverse_iterator>;
|
||||||
const BinaryBasicBlock> const_reverse_iterator;
|
|
||||||
|
|
||||||
typedef BasicBlockOrderType::iterator order_iterator;
|
typedef BasicBlockOrderType::iterator order_iterator;
|
||||||
typedef BasicBlockOrderType::const_iterator const_order_iterator;
|
typedef BasicBlockOrderType::const_iterator const_order_iterator;
|
||||||
|
|
|
@ -12,10 +12,18 @@
|
||||||
#include "BinarySection.h"
|
#include "BinarySection.h"
|
||||||
#include "llvm/MC/MCContext.h"
|
#include "llvm/MC/MCContext.h"
|
||||||
#include "llvm/MC/MCStreamer.h"
|
#include "llvm/MC/MCStreamer.h"
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
|
||||||
|
#undef DEBUG_TYPE
|
||||||
|
#define DEBUG_TYPE "bolt"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace bolt;
|
using namespace bolt;
|
||||||
|
|
||||||
|
namespace opts {
|
||||||
|
extern cl::opt<bool> PrintRelocations;
|
||||||
|
}
|
||||||
|
|
||||||
Triple::ArchType Relocation::Arch;
|
Triple::ArchType Relocation::Arch;
|
||||||
|
|
||||||
bool Relocation::isSupported(uint64_t Type) {
|
bool Relocation::isSupported(uint64_t Type) {
|
||||||
|
@ -324,3 +332,29 @@ void Relocation::print(raw_ostream &OS) const {
|
||||||
OS << ", 0x" << Twine::utohexstr(Addend);
|
OS << ", 0x" << Twine::utohexstr(Addend);
|
||||||
OS << ", 0x" << Twine::utohexstr(Value);
|
OS << ", 0x" << Twine::utohexstr(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinarySection::~BinarySection() {
|
||||||
|
if (!isAllocatable() &&
|
||||||
|
(!hasSectionRef() ||
|
||||||
|
OutputContents.data() != getContents(Section).data())) {
|
||||||
|
delete[] getOutputData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinarySection::print(raw_ostream &OS) const {
|
||||||
|
OS << getName() << ", "
|
||||||
|
<< "0x" << Twine::utohexstr(getAddress()) << ", "
|
||||||
|
<< getSize()
|
||||||
|
<< " (0x" << Twine::utohexstr(getFileAddress()) << ", "
|
||||||
|
<< getOutputSize() << ")"
|
||||||
|
<< ", data = " << getData()
|
||||||
|
<< ", output data = " << getOutputData();
|
||||||
|
|
||||||
|
if (isAllocatable())
|
||||||
|
OS << " (allocatable)";
|
||||||
|
|
||||||
|
if (opts::PrintRelocations) {
|
||||||
|
for (auto &R : relocations())
|
||||||
|
OS << "\n " << R;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//===--- BinarySection.h - Interface for object file section -------------===//
|
//===--- BinarySection.h - Interface for object file section --------------===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
#ifndef LLVM_TOOLS_LLVM_BOLT_BINARY_SECTION_H
|
#ifndef LLVM_TOOLS_LLVM_BOLT_BINARY_SECTION_H
|
||||||
#define LLVM_TOOLS_LLVM_BOLT_BINARY_SECTION_H
|
#define LLVM_TOOLS_LLVM_BOLT_BINARY_SECTION_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/BinaryFormat/ELF.h"
|
#include "llvm/BinaryFormat/ELF.h"
|
||||||
#include "llvm/MC/MCSymbol.h"
|
#include "llvm/MC/MCSymbol.h"
|
||||||
|
@ -91,79 +92,167 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Relocation &Rel) {
|
||||||
return OS;
|
return OS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around SectionRef that also manages related relocations
|
inline uint8_t *copyByteArray(const uint8_t *Data, uint64_t Size) {
|
||||||
class BinarySection {
|
auto Array = new uint8_t[Size];
|
||||||
SectionRef Section;
|
memcpy(Array, Data, Size);
|
||||||
std::set<Relocation> Relocations;
|
return Array;
|
||||||
public:
|
}
|
||||||
explicit BinarySection(SectionRef Section) : Section(Section) { }
|
|
||||||
|
|
||||||
StringRef getName() const {
|
inline uint8_t *copyByteArray(StringRef Buffer) {
|
||||||
|
return copyByteArray(reinterpret_cast<const uint8_t*>(Buffer.data()),
|
||||||
|
Buffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t *copyByteArray(ArrayRef<char> Buffer) {
|
||||||
|
return copyByteArray(reinterpret_cast<const uint8_t*>(Buffer.data()),
|
||||||
|
Buffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A class to manage binary sections that also manages related relocations
|
||||||
|
class BinarySection {
|
||||||
|
friend class BinaryContext;
|
||||||
|
|
||||||
|
const std::string Name; // Section name
|
||||||
|
const SectionRef Section; // SectionRef (may be null)
|
||||||
|
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
|
||||||
|
unsigned Alignment; // alignment in bytes (must be > 0)
|
||||||
|
unsigned ELFType; // ELF section type
|
||||||
|
unsigned ELFFlags; // ELF section flags
|
||||||
|
bool IsLocal; // Is this a local section?
|
||||||
|
|
||||||
|
// Relocations associated with this section. Relocation offsets are
|
||||||
|
// wrt. to the original section address and size.
|
||||||
|
using RelocationSetType = std::set<Relocation>;
|
||||||
|
RelocationSetType Relocations;
|
||||||
|
|
||||||
|
// Pending relocations for this section. For the moment, just used by
|
||||||
|
// the .debug_info section. TODO: it would be nice to get rid of this.
|
||||||
|
RelocationSetType PendingRelocations;
|
||||||
|
|
||||||
|
// Output info
|
||||||
|
bool IsFinalized{false}; // Has this section had output information
|
||||||
|
// finalized?
|
||||||
|
uint64_t FileAddress{0}; // Section address for the rewritten binary.
|
||||||
|
uint64_t OutputSize{0}; // Section size in the rewritten binary.
|
||||||
|
uint64_t FileOffset{0}; // File offset in the rewritten binary file.
|
||||||
|
StringRef OutputContents; // Rewritten section contents.
|
||||||
|
unsigned SectionID{-1u}; // Unique ID used for address mapping.
|
||||||
|
// Set by ExecutableFileMemoryManager.
|
||||||
|
|
||||||
|
// non-copyable
|
||||||
|
BinarySection(const BinarySection &) = delete;
|
||||||
|
BinarySection(BinarySection &&) = delete;
|
||||||
|
BinarySection &operator=(const BinarySection &) = delete;
|
||||||
|
BinarySection &operator=(BinarySection &&) = delete;
|
||||||
|
|
||||||
|
static StringRef getName(SectionRef Section) {
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
Section.getName(Name);
|
Section.getName(Name);
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
uint64_t getAddress() const { return Section.getAddress(); }
|
static StringRef getContents(SectionRef Section) {
|
||||||
uint64_t getEndAddress() const { return getAddress() + getSize(); }
|
|
||||||
uint64_t getSize() const { return Section.getSize(); }
|
|
||||||
uint64_t getAlignment() const { return Section.getAlignment(); }
|
|
||||||
bool containsAddress(uint64_t Address) const {
|
|
||||||
return getAddress() <= Address && Address < getEndAddress();
|
|
||||||
}
|
|
||||||
bool containsRange(uint64_t Address, uint64_t Size) const {
|
|
||||||
return getAddress() <= Address && Address + Size <= getEndAddress();
|
|
||||||
}
|
|
||||||
bool isReadOnly() const { return Section.isReadOnly(); }
|
|
||||||
bool isVirtual() const { return Section.isVirtual(); }
|
|
||||||
bool isText() const { return Section.isText(); }
|
|
||||||
bool isAllocatable() const { return getFlags() & ELF::SHF_ALLOC; }
|
|
||||||
StringRef getContents() const {
|
|
||||||
StringRef Contents;
|
StringRef Contents;
|
||||||
|
if (ELFSectionRef(Section).getType() != ELF::SHT_NOBITS) {
|
||||||
if (auto EC = Section.getContents(Contents)) {
|
if (auto EC = Section.getContents(Contents)) {
|
||||||
errs() << "BOLT-ERROR: cannot get section contents for "
|
errs() << "BOLT-ERROR: cannot get section contents for "
|
||||||
<< getName() << ": " << EC.message() << ".\n";
|
<< getName(Section) << ": " << EC.message() << ".\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return Contents;
|
return Contents;
|
||||||
}
|
}
|
||||||
unsigned getFlags() const { return ELFSectionRef(Section).getFlags(); }
|
|
||||||
unsigned getType() const { return ELFSectionRef(Section).getType(); }
|
|
||||||
SectionRef getSectionRef() const { return Section; }
|
|
||||||
|
|
||||||
iterator_range<std::set<Relocation>::iterator> relocations() {
|
// Set output info for this section.
|
||||||
return make_range(Relocations.begin(), Relocations.end());
|
void update(uint8_t *NewData,
|
||||||
|
uint64_t NewSize,
|
||||||
|
unsigned NewAlignment,
|
||||||
|
unsigned NewELFType,
|
||||||
|
unsigned NewELFFlags,
|
||||||
|
bool NewIsLocal) {
|
||||||
|
assert(NewAlignment > 0 && "section alignment must be > 0");
|
||||||
|
OutputSize = NewSize;
|
||||||
|
Alignment = NewAlignment;
|
||||||
|
ELFType = NewELFType;
|
||||||
|
ELFFlags = NewELFFlags;
|
||||||
|
IsLocal = NewIsLocal || StringRef(Name).startswith(".local.");
|
||||||
|
OutputContents = StringRef(reinterpret_cast<const char*>(NewData),
|
||||||
|
NewData ? NewSize : 0);
|
||||||
|
IsFinalized = true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
explicit BinarySection(SectionRef Section, bool IsLocal = false)
|
||||||
|
: Name(getName(Section)),
|
||||||
|
Section(Section),
|
||||||
|
Contents(getContents(Section)),
|
||||||
|
Address(Section.getAddress()),
|
||||||
|
Size(Section.getSize()),
|
||||||
|
Alignment(Section.getAlignment()),
|
||||||
|
ELFType(ELFSectionRef(Section).getType()),
|
||||||
|
ELFFlags(ELFSectionRef(Section).getFlags()),
|
||||||
|
IsLocal(IsLocal || StringRef(Name).startswith(".local.")),
|
||||||
|
OutputSize(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator_range<std::set<Relocation>::const_iterator> relocations() const {
|
// TODO: pass Data as StringRef/ArrayRef? use StringRef::copy method.
|
||||||
return make_range(Relocations.begin(), Relocations.end());
|
BinarySection(StringRef Name,
|
||||||
|
uint8_t *Data,
|
||||||
|
uint64_t Size,
|
||||||
|
unsigned Alignment,
|
||||||
|
unsigned ELFType,
|
||||||
|
unsigned ELFFlags,
|
||||||
|
bool IsLocal)
|
||||||
|
: Name(Name),
|
||||||
|
Contents(reinterpret_cast<const char*>(Data), Data ? Size : 0),
|
||||||
|
Address(0),
|
||||||
|
Size(Size),
|
||||||
|
Alignment(Alignment),
|
||||||
|
ELFType(ELFType),
|
||||||
|
ELFFlags(ELFFlags),
|
||||||
|
IsLocal(IsLocal || Name.startswith(".local.")),
|
||||||
|
IsFinalized(true),
|
||||||
|
OutputSize(Size),
|
||||||
|
OutputContents(Contents) {
|
||||||
|
assert(Alignment > 0 && "section alignment must be > 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasRelocations() const {
|
~BinarySection();
|
||||||
return !Relocations.empty();
|
|
||||||
|
/// Helper function to generate the proper ELF flags from section properties.
|
||||||
|
static unsigned getFlags(bool IsReadOnly = true,
|
||||||
|
bool IsText = false,
|
||||||
|
bool IsAllocatable = false) {
|
||||||
|
unsigned Flags = 0;
|
||||||
|
if (IsAllocatable)
|
||||||
|
Flags |= ELF::SHF_ALLOC;
|
||||||
|
if (!IsReadOnly)
|
||||||
|
Flags |= ELF::SHF_WRITE;
|
||||||
|
if (IsText)
|
||||||
|
Flags |= ELF::SHF_EXECINSTR;
|
||||||
|
return Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeRelocationAt(uint64_t Offset) {
|
operator bool() const {
|
||||||
Relocation Key{Offset, 0, 0, 0, 0};
|
return ELFType != ELF::SHT_NULL;
|
||||||
auto Itr = Relocations.find(Key);
|
|
||||||
if (Itr != Relocations.end())
|
|
||||||
Relocations.erase(Itr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRelocation(uint64_t Offset,
|
bool operator==(const BinarySection &Other) const {
|
||||||
MCSymbol *Symbol,
|
return (Name == Other.Name &&
|
||||||
uint64_t Type,
|
Address == Other.Address &&
|
||||||
uint64_t Addend,
|
Size == Other.Size &&
|
||||||
uint64_t Value = 0) {
|
getData() == Other.getData() &&
|
||||||
assert(Offset < getSize());
|
Alignment == Other.Alignment &&
|
||||||
Relocations.emplace(Relocation{Offset, Symbol, Type, Addend, Value});
|
ELFType == Other.ELFType &&
|
||||||
|
ELFFlags == Other.ELFFlags &&
|
||||||
|
IsLocal == Other.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Relocation *getRelocationAt(uint64_t Offset) const {
|
bool operator!=(const BinarySection &Other) const {
|
||||||
Relocation Key{Offset, 0, 0, 0, 0};
|
return !operator==(Other);
|
||||||
auto Itr = Relocations.find(Key);
|
|
||||||
return Itr != Relocations.end() ? &*Itr : nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Order sections by their immutable properties.
|
||||||
bool operator<(const BinarySection &Other) const {
|
bool operator<(const BinarySection &Other) const {
|
||||||
return (getAddress() < Other.getAddress() ||
|
return (getAddress() < Other.getAddress() ||
|
||||||
(getAddress() == Other.getAddress() &&
|
(getAddress() == Other.getAddress() &&
|
||||||
|
@ -171,8 +260,170 @@ public:
|
||||||
(getSize() == Other.getSize() &&
|
(getSize() == Other.getSize() &&
|
||||||
getName() < Other.getName()))));
|
getName() < Other.getName()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Basic proprety access.
|
||||||
|
///
|
||||||
|
StringRef getName() const { return Name; }
|
||||||
|
uint64_t getAddress() const { return Address; }
|
||||||
|
uint64_t getEndAddress() const { return Address + Size; }
|
||||||
|
uint64_t getSize() const { return Size; }
|
||||||
|
uint64_t getAlignment() const { return Alignment; }
|
||||||
|
bool isText() const {
|
||||||
|
return (ELFFlags & ELF::SHF_EXECINSTR);
|
||||||
|
}
|
||||||
|
bool isData() const {
|
||||||
|
return (ELFType == ELF::SHT_PROGBITS &&
|
||||||
|
(ELFFlags & (ELF::SHF_ALLOC | ELF::SHF_WRITE)));
|
||||||
|
}
|
||||||
|
bool isBSS() const {
|
||||||
|
return (ELFType == ELF::SHT_NOBITS &&
|
||||||
|
(ELFFlags & (ELF::SHF_ALLOC | ELF::SHF_WRITE)));
|
||||||
|
}
|
||||||
|
bool isNote() const { return ELFType == ELF::SHT_NOTE; }
|
||||||
|
bool isStrTab() const { return ELFType == ELF::SHT_STRTAB; }
|
||||||
|
bool isSymTab() const { return ELFType == ELF::SHT_SYMTAB; }
|
||||||
|
bool isVirtual() const { return ELFType == ELF::SHT_NOBITS; }
|
||||||
|
bool isRela() const { return ELFType == ELF::SHT_RELA; }
|
||||||
|
bool isReadOnly() const {
|
||||||
|
return ((ELFFlags & ELF::SHF_ALLOC) &&
|
||||||
|
!(ELFFlags & ELF::SHF_WRITE) &&
|
||||||
|
ELFType == ELF::SHT_PROGBITS);
|
||||||
|
}
|
||||||
|
bool isAllocatable() const {
|
||||||
|
return (ELFFlags & ELF::SHF_ALLOC);
|
||||||
|
}
|
||||||
|
bool isLocal() const { return IsLocal; }
|
||||||
|
unsigned getELFType() const { return ELFType; }
|
||||||
|
unsigned getELFFlags() const { return ELFFlags; }
|
||||||
|
|
||||||
|
uint8_t *getData() {
|
||||||
|
return reinterpret_cast<uint8_t *>(const_cast<char *>(getContents().data()));
|
||||||
|
}
|
||||||
|
const uint8_t *getData() const {
|
||||||
|
return reinterpret_cast<const uint8_t *>(getContents().data());
|
||||||
|
}
|
||||||
|
StringRef getContents() const { return Contents; }
|
||||||
|
bool hasSectionRef() const { return Section != SectionRef(); }
|
||||||
|
SectionRef getSectionRef() const { return Section; }
|
||||||
|
|
||||||
|
/// Does this section contain the given /p Addr?
|
||||||
|
/// Note: this is in terms of the original mapped binary addresses.
|
||||||
|
bool containsAddress(uint64_t Addr) const {
|
||||||
|
return getAddress() <= Addr && Addr < getEndAddress();
|
||||||
|
}
|
||||||
|
/// Does this section contain the range given by /p Addr and /p Sz?
|
||||||
|
/// Note: this is in terms of the original mapped binary addresses.
|
||||||
|
bool containsRange(uint64_t Addr, uint64_t Sz) const {
|
||||||
|
return getAddress() <= Addr && Addr + Sz <= getEndAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over all non-pending relocations for this section.
|
||||||
|
iterator_range<RelocationSetType::iterator> relocations() {
|
||||||
|
return make_range(Relocations.begin(), Relocations.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over all non-pending relocations for this section.
|
||||||
|
iterator_range<RelocationSetType::const_iterator> relocations() const {
|
||||||
|
return make_range(Relocations.begin(), Relocations.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does this section have any non-pending relocations?
|
||||||
|
bool hasRelocations() const {
|
||||||
|
return !Relocations.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over all pending relocations in this section.
|
||||||
|
iterator_range<RelocationSetType::const_iterator> pendingRelocations() const {
|
||||||
|
return make_range(PendingRelocations.begin(), PendingRelocations.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does this section have any pending relocations?
|
||||||
|
bool hasPendingRelocations() const {
|
||||||
|
return !PendingRelocations.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove non-pending relocation with the given /p Offset.
|
||||||
|
bool removeRelocationAt(uint64_t Offset) {
|
||||||
|
Relocation Key{Offset, 0, 0, 0, 0};
|
||||||
|
auto Itr = Relocations.find(Key);
|
||||||
|
if (Itr != Relocations.end()) {
|
||||||
|
Relocations.erase(Itr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new relocation at the given /p Offset. Note: pending relocations
|
||||||
|
/// are only used by .debug_info and should eventually go away.
|
||||||
|
void addRelocation(uint64_t Offset,
|
||||||
|
MCSymbol *Symbol,
|
||||||
|
uint64_t Type,
|
||||||
|
uint64_t Addend,
|
||||||
|
uint64_t Value = 0,
|
||||||
|
bool Pending = false) {
|
||||||
|
assert(Offset < getSize() && "offset not within section bounds");
|
||||||
|
if (!Pending) {
|
||||||
|
Relocations.emplace(Relocation{Offset, Symbol, Type, Addend, Value});
|
||||||
|
} else {
|
||||||
|
PendingRelocations.emplace(Relocation{Offset, Symbol, Type, Addend, Value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lookup the relocation (if any) at the given /p Offset.
|
||||||
|
const Relocation *getRelocationAt(uint64_t Offset) const {
|
||||||
|
Relocation Key{Offset, 0, 0, 0, 0};
|
||||||
|
auto Itr = Relocations.find(Key);
|
||||||
|
return Itr != Relocations.end() ? &*Itr : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Property accessors related to output data.
|
||||||
|
///
|
||||||
|
|
||||||
|
bool isFinalized() const { return IsFinalized; }
|
||||||
|
void setIsFinalized() { IsFinalized = true; }
|
||||||
|
uint64_t getOutputSize() const { return OutputSize; }
|
||||||
|
uint8_t *getOutputData() {
|
||||||
|
return reinterpret_cast<uint8_t *>(const_cast<char *>(getOutputContents().data()));
|
||||||
|
}
|
||||||
|
const uint8_t *getOutputData() const {
|
||||||
|
return reinterpret_cast<const uint8_t *>(getOutputContents().data());
|
||||||
|
}
|
||||||
|
StringRef getOutputContents() const { return OutputContents; }
|
||||||
|
uint64_t getAllocAddress() const {
|
||||||
|
return reinterpret_cast<uint64_t>(getOutputData());
|
||||||
|
}
|
||||||
|
uint64_t getFileAddress() const { return FileAddress; }
|
||||||
|
uint64_t getFileOffset() const { return FileOffset; }
|
||||||
|
unsigned getSectionID() const {
|
||||||
|
assert(hasValidSectionID() && "trying to use uninitialized section id");
|
||||||
|
return SectionID;
|
||||||
|
}
|
||||||
|
bool hasValidSectionID() const {
|
||||||
|
return SectionID != -1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mutation
|
||||||
|
void setFileAddress(uint64_t Address) {
|
||||||
|
FileAddress = Address;
|
||||||
|
}
|
||||||
|
void setFileOffset(uint64_t Offset) {
|
||||||
|
FileOffset = Offset;
|
||||||
|
}
|
||||||
|
void setSectionID(unsigned ID) {
|
||||||
|
assert(!hasValidSectionID() && "trying to set section id twice");
|
||||||
|
SectionID = ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(raw_ostream &OS) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline raw_ostream &operator<<(raw_ostream &OS, const BinarySection &Section) {
|
||||||
|
Section.print(OS);
|
||||||
|
return OS;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bolt
|
} // namespace bolt
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
|
||||||
|
|
|
@ -444,9 +444,19 @@ void RewriteInstance::updateLineTableOffsets() {
|
||||||
Offset += Label->getOffset() - CurrentOffset;
|
Offset += Label->getOffset() - CurrentOffset;
|
||||||
CurrentOffset = Label->getOffset();
|
CurrentOffset = Label->getOffset();
|
||||||
|
|
||||||
auto &SI = EFMM->NoteSectionInfo[".debug_info"];
|
auto DbgInfoSection = BC->getUniqueSectionByName(".debug_info");
|
||||||
SI.PendingRelocs.emplace_back(
|
assert(DbgInfoSection && ".debug_info section must exist");
|
||||||
SectionInfo::Reloc{LTOffset, 4, 0, Offset});
|
auto *Zero = BC->registerNameAtAddress("Zero", 0);
|
||||||
|
DbgInfoSection->addRelocation(LTOffset,
|
||||||
|
Zero,
|
||||||
|
ELF::R_X86_64_32,
|
||||||
|
Offset,
|
||||||
|
0,
|
||||||
|
/*Pending=*/true);
|
||||||
|
// Set .debug_info as finalized so it won't be skipped over when
|
||||||
|
// we process sections while writing out the new binary. This ensures
|
||||||
|
// that the pending relocations will be processed and not ignored.
|
||||||
|
DbgInfoSection->setIsFinalized();
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: CU " << CUIDLineTablePair.first
|
DEBUG(dbgs() << "BOLT-DEBUG: CU " << CUIDLineTablePair.first
|
||||||
<< " has line table at " << Offset << "\n");
|
<< " has line table at " << Offset << "\n");
|
||||||
|
@ -466,41 +476,20 @@ void RewriteInstance::finalizeDebugSections() {
|
||||||
RangesSectionsWriter->writeArangesSection(Writer.get());
|
RangesSectionsWriter->writeArangesSection(Writer.get());
|
||||||
const auto &ARangesContents = OS.str();
|
const auto &ARangesContents = OS.str();
|
||||||
|
|
||||||
// Freed by ExecutableFileMemoryManager.
|
BC->registerOrUpdateNoteSection(".debug_aranges",
|
||||||
uint8_t *SectionData = new uint8_t[ARangesContents.size()];
|
copyByteArray(ARangesContents),
|
||||||
memcpy(SectionData, ARangesContents.data(), ARangesContents.size());
|
ARangesContents.size());
|
||||||
EFMM->NoteSectionInfo[".debug_aranges"] = SectionInfo(
|
|
||||||
reinterpret_cast<uint64_t>(SectionData),
|
|
||||||
ARangesContents.size(),
|
|
||||||
/*Alignment=*/0,
|
|
||||||
/*IsCode=*/false,
|
|
||||||
/*IsReadOnly=*/true,
|
|
||||||
/*IsLocal=*/false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto RangesSectionContents = RangesSectionsWriter->finalize();
|
auto RangesSectionContents = RangesSectionsWriter->finalize();
|
||||||
auto SectionSize = RangesSectionContents->size();
|
BC->registerOrUpdateNoteSection(".debug_ranges",
|
||||||
uint8_t *SectionData = new uint8_t[SectionSize];
|
copyByteArray(*RangesSectionContents),
|
||||||
memcpy(SectionData, RangesSectionContents->data(), SectionSize);
|
RangesSectionContents->size());
|
||||||
EFMM->NoteSectionInfo[".debug_ranges"] = SectionInfo(
|
|
||||||
reinterpret_cast<uint64_t>(SectionData),
|
|
||||||
SectionSize,
|
|
||||||
/*Alignment=*/1,
|
|
||||||
/*IsCode=*/false,
|
|
||||||
/*IsReadOnly=*/true,
|
|
||||||
/*IsLocal=*/false);
|
|
||||||
|
|
||||||
auto LocationListSectionContents = LocationListWriter->finalize();
|
auto LocationListSectionContents = LocationListWriter->finalize();
|
||||||
SectionSize = LocationListSectionContents->size();
|
BC->registerOrUpdateNoteSection(".debug_loc",
|
||||||
SectionData = new uint8_t[SectionSize];
|
copyByteArray(*LocationListSectionContents),
|
||||||
memcpy(SectionData, LocationListSectionContents->data(), SectionSize);
|
LocationListSectionContents->size());
|
||||||
EFMM->NoteSectionInfo[".debug_loc"] = SectionInfo(
|
|
||||||
reinterpret_cast<uint64_t>(SectionData),
|
|
||||||
SectionSize,
|
|
||||||
/*Alignment=*/1,
|
|
||||||
/*IsCode=*/false,
|
|
||||||
/*IsReadOnly=*/true,
|
|
||||||
/*IsLocal=*/false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RewriteInstance::updateGdbIndexSection() {
|
void RewriteInstance::updateGdbIndexSection() {
|
||||||
|
@ -569,7 +558,7 @@ void RewriteInstance::updateGdbIndexSection() {
|
||||||
size_t NewGdbIndexSize = GdbIndexContents.size() + Delta;
|
size_t NewGdbIndexSize = GdbIndexContents.size() + Delta;
|
||||||
|
|
||||||
// Free'd by ExecutableFileMemoryManager.
|
// Free'd by ExecutableFileMemoryManager.
|
||||||
auto * const NewGdbIndexContents = new uint8_t[NewGdbIndexSize];
|
auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize];
|
||||||
auto *Buffer = NewGdbIndexContents;
|
auto *Buffer = NewGdbIndexContents;
|
||||||
|
|
||||||
write32le(Buffer, Version);
|
write32le(Buffer, Version);
|
||||||
|
@ -606,11 +595,7 @@ void RewriteInstance::updateGdbIndexSection() {
|
||||||
memcpy(Buffer, Data, TrailingSize);
|
memcpy(Buffer, Data, TrailingSize);
|
||||||
|
|
||||||
// Register the new section.
|
// Register the new section.
|
||||||
EFMM->NoteSectionInfo[".gdb_index"] = SectionInfo(
|
BC->registerOrUpdateNoteSection(".gdb_index",
|
||||||
reinterpret_cast<uint64_t>(NewGdbIndexContents),
|
NewGdbIndexContents,
|
||||||
NewGdbIndexSize,
|
NewGdbIndexSize);
|
||||||
/*Alignment=*/0,
|
|
||||||
/*IsCode=*/false,
|
|
||||||
/*IsReadOnly=*/true,
|
|
||||||
/*IsLocal=*/false);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,6 +220,13 @@ PrintDisasm("print-disasm",
|
||||||
cl::Hidden,
|
cl::Hidden,
|
||||||
cl::cat(BoltCategory));
|
cl::cat(BoltCategory));
|
||||||
|
|
||||||
|
static cl::opt<bool>
|
||||||
|
PrintSections("print-sections",
|
||||||
|
cl::desc("print all registered sections"),
|
||||||
|
cl::ZeroOrMore,
|
||||||
|
cl::Hidden,
|
||||||
|
cl::cat(BoltCategory));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
PrintLoopInfo("print-loops",
|
PrintLoopInfo("print-loops",
|
||||||
cl::desc("print loop related information"),
|
cl::desc("print loop related information"),
|
||||||
|
@ -459,55 +466,44 @@ uint8_t *ExecutableFileMemoryManager::allocateSection(intptr_t Size,
|
||||||
for (auto &OverwriteName : RewriteInstance::SectionsToOverwrite) {
|
for (auto &OverwriteName : RewriteInstance::SectionsToOverwrite) {
|
||||||
if (SectionName == OverwriteName) {
|
if (SectionName == OverwriteName) {
|
||||||
uint8_t *DataCopy = new uint8_t[Size];
|
uint8_t *DataCopy = new uint8_t[Size];
|
||||||
DEBUG(dbgs() << "BOLT: note section " << SectionName << " with size "
|
auto &Section = BC.registerOrUpdateNoteSection(SectionName,
|
||||||
<< Size << ", alignment " << Alignment << " at 0x"
|
DataCopy,
|
||||||
<< Twine::utohexstr(reinterpret_cast<uint64_t>(DataCopy))
|
|
||||||
<< '\n');
|
|
||||||
NoteSectionInfo[SectionName] =
|
|
||||||
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
|
|
||||||
Size,
|
Size,
|
||||||
Alignment,
|
Alignment);
|
||||||
/*IsCode=*/false,
|
Section.setSectionID(SectionID);
|
||||||
/*IsReadOnly=*/true,
|
assert(!Section.isAllocatable() && "note sections cannot be allocatable");
|
||||||
/*IsLocal=*/false,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
SectionID);
|
|
||||||
return DataCopy;
|
return DataCopy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *ret;
|
uint8_t *Ret;
|
||||||
if (IsCode) {
|
if (IsCode) {
|
||||||
ret = SectionMemoryManager::allocateCodeSection(Size, Alignment,
|
Ret = SectionMemoryManager::allocateCodeSection(Size, Alignment,
|
||||||
SectionID, SectionName);
|
SectionID, SectionName);
|
||||||
} else {
|
} else {
|
||||||
ret = SectionMemoryManager::allocateDataSection(Size, Alignment,
|
Ret = SectionMemoryManager::allocateDataSection(Size, Alignment,
|
||||||
SectionID, SectionName,
|
SectionID, SectionName,
|
||||||
IsReadOnly);
|
IsReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLocal = false;
|
const auto Flags = BinarySection::getFlags(IsReadOnly, IsCode, true);
|
||||||
if (SectionName.startswith(".local."))
|
auto &Section = BC.registerOrUpdateSection(SectionName,
|
||||||
IsLocal = true;
|
ELF::SHT_PROGBITS,
|
||||||
|
Flags,
|
||||||
|
Ret,
|
||||||
|
Size,
|
||||||
|
Alignment);
|
||||||
|
Section.setSectionID(SectionID);
|
||||||
|
assert(Section.isAllocatable() &&
|
||||||
|
"verify that allocatable is marked as allocatable");
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT: allocating " << (IsLocal ? "local " : "")
|
DEBUG(dbgs() << "BOLT: allocating " << (Section.isLocal() ? "local " : "")
|
||||||
<< (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
|
<< (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
|
||||||
<< " section : " << SectionName
|
<< " section : " << SectionName
|
||||||
<< " with size " << Size << ", alignment " << Alignment
|
<< " with size " << Size << ", alignment " << Alignment
|
||||||
<< " at 0x" << ret << "\n");
|
<< " at 0x" << Ret << ", ID = " << SectionID << "\n");
|
||||||
|
|
||||||
SectionMapInfo[SectionName] = SectionInfo(reinterpret_cast<uint64_t>(ret),
|
return Ret;
|
||||||
Size,
|
|
||||||
Alignment,
|
|
||||||
IsCode,
|
|
||||||
IsReadOnly,
|
|
||||||
IsLocal,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
SectionID);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notifier for non-allocatable (note) section.
|
/// Notifier for non-allocatable (note) section.
|
||||||
|
@ -522,21 +518,13 @@ uint8_t *ExecutableFileMemoryManager::recordNoteSection(
|
||||||
<< " with size " << Size << ", alignment " << Alignment
|
<< " with size " << Size << ", alignment " << Alignment
|
||||||
<< " at 0x"
|
<< " at 0x"
|
||||||
<< Twine::utohexstr(reinterpret_cast<uint64_t>(Data)) << '\n');
|
<< Twine::utohexstr(reinterpret_cast<uint64_t>(Data)) << '\n');
|
||||||
// We need to make a copy of the section contents if we'll need it for
|
auto &Section = BC.registerOrUpdateNoteSection(SectionName,
|
||||||
// a future reference. RuntimeDyld will not allocate the space forus.
|
copyByteArray(Data, Size),
|
||||||
uint8_t *DataCopy = new uint8_t[Size];
|
|
||||||
memcpy(DataCopy, Data, Size);
|
|
||||||
NoteSectionInfo[SectionName] =
|
|
||||||
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
|
|
||||||
Size,
|
Size,
|
||||||
Alignment,
|
Alignment);
|
||||||
/*IsCode=*/false,
|
Section.setSectionID(SectionID);
|
||||||
/*IsReadOnly=*/true,
|
assert(!Section.isAllocatable() && "note sections cannot be allocatable");
|
||||||
/*IsLocal=*/false,
|
return Section.getOutputData();
|
||||||
0,
|
|
||||||
0,
|
|
||||||
SectionID);
|
|
||||||
return DataCopy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExecutableFileMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
bool ExecutableFileMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
||||||
|
@ -544,11 +532,7 @@ bool ExecutableFileMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
||||||
return SectionMemoryManager::finalizeMemory(ErrMsg);
|
return SectionMemoryManager::finalizeMemory(ErrMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutableFileMemoryManager::~ExecutableFileMemoryManager() {
|
ExecutableFileMemoryManager::~ExecutableFileMemoryManager() { }
|
||||||
for (auto &SII : NoteSectionInfo) {
|
|
||||||
delete[] reinterpret_cast<uint8_t *>(SII.second.AllocAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -717,8 +701,7 @@ void RewriteInstance::discoverStorage() {
|
||||||
// sections accounting for stubs when we need those sections to match the
|
// sections accounting for stubs when we need those sections to match the
|
||||||
// same size seen in the input binary, in case this section is a copy
|
// same size seen in the input binary, in case this section is a copy
|
||||||
// of the original one seen in the binary.
|
// of the original one seen in the binary.
|
||||||
EFMM.reset(new ExecutableFileMemoryManager(
|
EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false));
|
||||||
/*AllowStubs*/ false));
|
|
||||||
|
|
||||||
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
|
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
|
||||||
if (!ELF64LEFile) {
|
if (!ELF64LEFile) {
|
||||||
|
@ -1285,9 +1268,10 @@ void RewriteInstance::discoverFileObjects() {
|
||||||
}
|
}
|
||||||
BF->addAlternativeName(UniqueName);
|
BF->addAlternativeName(UniqueName);
|
||||||
} else {
|
} else {
|
||||||
auto BS = BC->getSectionForAddress(Address);
|
auto Section = BC->getSectionForAddress(Address);
|
||||||
assert(BS && "section for functions must be registered.");
|
assert(Section && "section for functions must be registered.");
|
||||||
BF = createBinaryFunction(UniqueName, *BS, Address, SymbolSize, IsSimple);
|
BF = createBinaryFunction(UniqueName, *Section, Address,
|
||||||
|
SymbolSize, IsSimple);
|
||||||
}
|
}
|
||||||
if (!AlternativeName.empty())
|
if (!AlternativeName.empty())
|
||||||
BF->addAlternativeName(AlternativeName);
|
BF->addAlternativeName(AlternativeName);
|
||||||
|
@ -1521,8 +1505,8 @@ void RewriteInstance::relocateEHFrameSection() {
|
||||||
assert(EHFrameSection && "non-empty .eh_frame section expected");
|
assert(EHFrameSection && "non-empty .eh_frame section expected");
|
||||||
|
|
||||||
DWARFDebugFrame EHFrame(true, EHFrameSection->getAddress());
|
DWARFDebugFrame EHFrame(true, EHFrameSection->getAddress());
|
||||||
StringRef EHFrameSectionContents = EHFrameSection->getContents();
|
DWARFDataExtractor DE(EHFrameSection->getContents(),
|
||||||
DWARFDataExtractor DE(EHFrameSectionContents, BC->AsmInfo->isLittleEndian(),
|
BC->AsmInfo->isLittleEndian(),
|
||||||
BC->AsmInfo->getCodePointerSize());
|
BC->AsmInfo->getCodePointerSize());
|
||||||
auto createReloc = [&](uint64_t Value, uint64_t Offset, uint64_t DwarfType) {
|
auto createReloc = [&](uint64_t Value, uint64_t Offset, uint64_t DwarfType) {
|
||||||
if (DwarfType == dwarf::DW_EH_PE_omit)
|
if (DwarfType == dwarf::DW_EH_PE_omit)
|
||||||
|
@ -1564,7 +1548,7 @@ void RewriteInstance::relocateEHFrameSection() {
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: adding DWARF reference against symbol "
|
DEBUG(dbgs() << "BOLT-DEBUG: adding DWARF reference against symbol "
|
||||||
<< Symbol->getName() << '\n');
|
<< Symbol->getName() << '\n');
|
||||||
|
|
||||||
BC->addSectionRelocation(*EHFrameSection, Offset, Symbol, RelType);
|
EHFrameSection->addRelocation(Offset, Symbol, RelType, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
EHFrame.parse(DE, createReloc);
|
EHFrame.parse(DE, createReloc);
|
||||||
|
@ -1594,7 +1578,7 @@ void RewriteInstance::readSpecialSections() {
|
||||||
check_error(Section.getName(SectionName), "cannot get section name");
|
check_error(Section.getName(SectionName), "cannot get section name");
|
||||||
StringRef SectionContents;
|
StringRef SectionContents;
|
||||||
ArrayRef<uint8_t> SectionData;
|
ArrayRef<uint8_t> SectionData;
|
||||||
if (!(ELFSectionRef(Section).getType() & ELF::SHT_NOBITS)) {
|
if (ELFSectionRef(Section).getType() != ELF::SHT_NOBITS) {
|
||||||
check_error(Section.getContents(SectionContents),
|
check_error(Section.getContents(SectionContents),
|
||||||
"cannot get section contents");
|
"cannot get section contents");
|
||||||
SectionData = ArrayRef<uint8_t>(
|
SectionData = ArrayRef<uint8_t>(
|
||||||
|
@ -1611,12 +1595,20 @@ void RewriteInstance::readSpecialSections() {
|
||||||
HasTextRelocations = true;
|
HasTextRelocations = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only register sections with names.
|
||||||
|
if (!getSectionName(Section).empty()) {
|
||||||
BC->registerSection(Section);
|
BC->registerSection(Section);
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: registering section " << SectionName
|
DEBUG(dbgs() << "BOLT-DEBUG: registering section " << SectionName
|
||||||
<< " @ 0x" << Twine::utohexstr(Section.getAddress()) << ":0x"
|
<< " @ 0x" << Twine::utohexstr(Section.getAddress()) << ":0x"
|
||||||
<< Twine::utohexstr(Section.getAddress() + Section.getSize())
|
<< Twine::utohexstr(Section.getAddress() + Section.getSize())
|
||||||
<< "\n");
|
<< "\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts::PrintSections) {
|
||||||
|
outs() << "BOLT-INFO: Sections from original binary:\n";
|
||||||
|
BC->printSections(outs());
|
||||||
|
}
|
||||||
|
|
||||||
EHFrameSection = BC->getUniqueSectionByName(".eh_frame");
|
EHFrameSection = BC->getUniqueSectionByName(".eh_frame");
|
||||||
GdbIndexSection = BC->getUniqueSectionByName(".gdb_index");
|
GdbIndexSection = BC->getUniqueSectionByName(".gdb_index");
|
||||||
|
@ -2549,19 +2541,18 @@ void RewriteInstance::mapFileSections(
|
||||||
orc::RTDyldObjectLinkingLayer::ObjHandleT &ObjectsHandle) {
|
orc::RTDyldObjectLinkingLayer::ObjHandleT &ObjectsHandle) {
|
||||||
NewTextSectionStartAddress = NextAvailableAddress;
|
NewTextSectionStartAddress = NextAvailableAddress;
|
||||||
if (BC->HasRelocations) {
|
if (BC->HasRelocations) {
|
||||||
auto SMII = EFMM->SectionMapInfo.find(".text");
|
auto TextSection = BC->getUniqueSectionByName(".text");
|
||||||
assert(SMII != EFMM->SectionMapInfo.end() &&
|
assert(TextSection && ".text not found in output");
|
||||||
".text not found in output");
|
|
||||||
auto &SI = SMII->second;
|
|
||||||
|
|
||||||
uint64_t NewTextSectionOffset = 0;
|
uint64_t NewTextSectionOffset = 0;
|
||||||
if (opts::UseOldText && SI.Size <= BC->OldTextSectionSize) {
|
if (opts::UseOldText &&
|
||||||
|
TextSection->getOutputSize() <= BC->OldTextSectionSize) {
|
||||||
outs() << "BOLT-INFO: using original .text for new code\n";
|
outs() << "BOLT-INFO: using original .text for new code\n";
|
||||||
// Utilize the original .text for storage.
|
// Utilize the original .text for storage.
|
||||||
NewTextSectionStartAddress = BC->OldTextSectionAddress;
|
NewTextSectionStartAddress = BC->OldTextSectionAddress;
|
||||||
NewTextSectionOffset = BC->OldTextSectionOffset;
|
NewTextSectionOffset = BC->OldTextSectionOffset;
|
||||||
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
|
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
|
||||||
if (Padding + SI.Size <= BC->OldTextSectionSize) {
|
if (Padding + TextSection->getOutputSize() <= BC->OldTextSectionSize) {
|
||||||
outs() << "BOLT-INFO: using 0x200000 alignment\n";
|
outs() << "BOLT-INFO: using 0x200000 alignment\n";
|
||||||
NewTextSectionStartAddress += Padding;
|
NewTextSectionStartAddress += Padding;
|
||||||
NewTextSectionOffset += Padding;
|
NewTextSectionOffset += Padding;
|
||||||
|
@ -2569,24 +2560,24 @@ void RewriteInstance::mapFileSections(
|
||||||
} else {
|
} else {
|
||||||
if (opts::UseOldText) {
|
if (opts::UseOldText) {
|
||||||
errs() << "BOLT-ERROR: original .text too small to fit the new code. "
|
errs() << "BOLT-ERROR: original .text too small to fit the new code. "
|
||||||
<< SI.Size << " bytes needed, have " << BC->OldTextSectionSize
|
<< TextSection->getOutputSize() << " bytes needed, have "
|
||||||
<< " bytes available.\n";
|
<< BC->OldTextSectionSize << " bytes available.\n";
|
||||||
}
|
}
|
||||||
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
|
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
|
||||||
NextAvailableAddress += Padding;
|
NextAvailableAddress += Padding;
|
||||||
NewTextSectionStartAddress = NextAvailableAddress;
|
NewTextSectionStartAddress = NextAvailableAddress;
|
||||||
NewTextSectionOffset = getFileOffsetForAddress(NextAvailableAddress);
|
NewTextSectionOffset = getFileOffsetForAddress(NextAvailableAddress);
|
||||||
NextAvailableAddress += Padding + SI.Size;
|
NextAvailableAddress += Padding + TextSection->getOutputSize();
|
||||||
}
|
}
|
||||||
SI.FileAddress = NewTextSectionStartAddress;
|
TextSection->setFileAddress(NewTextSectionStartAddress);
|
||||||
SI.FileOffset = NewTextSectionOffset;
|
TextSection->setFileOffset(NewTextSectionOffset);
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT: mapping .text 0x"
|
DEBUG(dbgs() << "BOLT: mapping .text 0x"
|
||||||
<< Twine::utohexstr(SMII->second.AllocAddress)
|
<< Twine::utohexstr(TextSection->getAllocAddress())
|
||||||
<< " to 0x" << Twine::utohexstr(NewTextSectionStartAddress)
|
<< " to 0x" << Twine::utohexstr(NewTextSectionStartAddress)
|
||||||
<< '\n');
|
<< '\n');
|
||||||
OLT->mapSectionAddress(ObjectsHandle,
|
OLT->mapSectionAddress(ObjectsHandle,
|
||||||
SI.SectionID,
|
TextSection->getSectionID(),
|
||||||
NewTextSectionStartAddress);
|
NewTextSectionStartAddress);
|
||||||
} else {
|
} else {
|
||||||
for (auto &BFI : BinaryFunctions) {
|
for (auto &BFI : BinaryFunctions) {
|
||||||
|
@ -2595,18 +2586,17 @@ void RewriteInstance::mapFileSections(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto TooLarge = false;
|
auto TooLarge = false;
|
||||||
auto SMII = EFMM->SectionMapInfo.find(Function.getCodeSectionName());
|
auto FuncSection = BC->getUniqueSectionByName(Function.getCodeSectionName());
|
||||||
assert(SMII != EFMM->SectionMapInfo.end() &&
|
assert(FuncSection && "cannot find section for function");
|
||||||
"cannot find section for function");
|
|
||||||
DEBUG(dbgs() << "BOLT: mapping 0x"
|
DEBUG(dbgs() << "BOLT: mapping 0x"
|
||||||
<< Twine::utohexstr(SMII->second.AllocAddress)
|
<< Twine::utohexstr(FuncSection->getAllocAddress())
|
||||||
<< " to 0x" << Twine::utohexstr(Function.getAddress())
|
<< " to 0x" << Twine::utohexstr(Function.getAddress())
|
||||||
<< '\n');
|
<< '\n');
|
||||||
OLT->mapSectionAddress(ObjectsHandle,
|
OLT->mapSectionAddress(ObjectsHandle,
|
||||||
SMII->second.SectionID,
|
FuncSection->getSectionID(),
|
||||||
Function.getAddress());
|
Function.getAddress());
|
||||||
Function.setImageAddress(SMII->second.AllocAddress);
|
Function.setImageAddress(FuncSection->getAllocAddress());
|
||||||
Function.setImageSize(SMII->second.Size);
|
Function.setImageSize(FuncSection->getOutputSize());
|
||||||
if (Function.getImageSize() > Function.getMaxSize()) {
|
if (Function.getImageSize() > Function.getMaxSize()) {
|
||||||
TooLarge = true;
|
TooLarge = true;
|
||||||
FailedAddresses.emplace_back(Function.getAddress());
|
FailedAddresses.emplace_back(Function.getAddress());
|
||||||
|
@ -2616,15 +2606,13 @@ void RewriteInstance::mapFileSections(
|
||||||
if (opts::JumpTables == JTS_BASIC) {
|
if (opts::JumpTables == JTS_BASIC) {
|
||||||
for (auto &JTI : Function.JumpTables) {
|
for (auto &JTI : Function.JumpTables) {
|
||||||
auto &JT = JTI.second;
|
auto &JT = JTI.second;
|
||||||
auto SMII = EFMM->SectionMapInfo.find(JT.SectionName);
|
JT.Section = BC->getUniqueSectionByName(JT.SectionName);
|
||||||
assert(SMII != EFMM->SectionMapInfo.end() &&
|
assert(JT.Section && "cannot find section for jump table");
|
||||||
"cannot find section for jump table");
|
JT.Section->setFileAddress(JT.Address);
|
||||||
JT.SecInfo = &SMII->second;
|
|
||||||
JT.SecInfo->FileAddress = JT.Address;
|
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: mapping " << JT.SectionName << " to 0x"
|
DEBUG(dbgs() << "BOLT-DEBUG: mapping " << JT.SectionName << " to 0x"
|
||||||
<< Twine::utohexstr(JT.Address) << '\n');
|
<< Twine::utohexstr(JT.Address) << '\n');
|
||||||
OLT->mapSectionAddress(ObjectsHandle,
|
OLT->mapSectionAddress(ObjectsHandle,
|
||||||
JT.SecInfo->SectionID,
|
JT.Section->getSectionID(),
|
||||||
JT.Address);
|
JT.Address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2632,9 +2620,9 @@ void RewriteInstance::mapFileSections(
|
||||||
if (!Function.isSplit())
|
if (!Function.isSplit())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SMII = EFMM->SectionMapInfo.find(Function.getColdCodeSectionName());
|
auto ColdSection =
|
||||||
assert(SMII != EFMM->SectionMapInfo.end() &&
|
BC->getUniqueSectionByName(Function.getColdCodeSectionName());
|
||||||
"cannot find section for cold part");
|
assert(ColdSection && "cannot find section for cold part");
|
||||||
// Cold fragments are aligned at 16 bytes.
|
// Cold fragments are aligned at 16 bytes.
|
||||||
NextAvailableAddress = alignTo(NextAvailableAddress, 16);
|
NextAvailableAddress = alignTo(NextAvailableAddress, 16);
|
||||||
auto &ColdPart = Function.cold();
|
auto &ColdPart = Function.cold();
|
||||||
|
@ -2646,8 +2634,8 @@ void RewriteInstance::mapFileSections(
|
||||||
ColdPart.setFileOffset(0);
|
ColdPart.setFileOffset(0);
|
||||||
} else {
|
} else {
|
||||||
ColdPart.setAddress(NextAvailableAddress);
|
ColdPart.setAddress(NextAvailableAddress);
|
||||||
ColdPart.setImageAddress(SMII->second.AllocAddress);
|
ColdPart.setImageAddress(ColdSection->getAllocAddress());
|
||||||
ColdPart.setImageSize(SMII->second.Size);
|
ColdPart.setImageSize(ColdSection->getOutputSize());
|
||||||
ColdPart.setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
|
ColdPart.setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2658,7 +2646,7 @@ void RewriteInstance::mapFileSections(
|
||||||
<< " with size "
|
<< " with size "
|
||||||
<< Twine::utohexstr(ColdPart.getImageSize()) << '\n');
|
<< Twine::utohexstr(ColdPart.getImageSize()) << '\n');
|
||||||
OLT->mapSectionAddress(ObjectsHandle,
|
OLT->mapSectionAddress(ObjectsHandle,
|
||||||
SMII->second.SectionID,
|
ColdSection->getSectionID(),
|
||||||
ColdPart.getAddress());
|
ColdPart.getAddress());
|
||||||
|
|
||||||
NextAvailableAddress += ColdPart.getImageSize();
|
NextAvailableAddress += ColdPart.getImageSize();
|
||||||
|
@ -2669,14 +2657,18 @@ void RewriteInstance::mapFileSections(
|
||||||
// entry in section header table.
|
// entry in section header table.
|
||||||
auto NewTextSectionSize = NextAvailableAddress - NewTextSectionStartAddress;
|
auto NewTextSectionSize = NextAvailableAddress - NewTextSectionStartAddress;
|
||||||
if (NewTextSectionSize) {
|
if (NewTextSectionSize) {
|
||||||
EFMM->SectionMapInfo[BOLTSecPrefix + ".text"] =
|
const auto Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
|
||||||
SectionInfo(0,
|
/*IsText=*/true,
|
||||||
|
/*IsAllocatable=*/true);
|
||||||
|
auto &Section = BC->registerOrUpdateSection(BOLTSecPrefix + ".text",
|
||||||
|
ELF::SHT_PROGBITS,
|
||||||
|
Flags,
|
||||||
|
nullptr,
|
||||||
NewTextSectionSize,
|
NewTextSectionSize,
|
||||||
16,
|
16,
|
||||||
true /*IsCode*/,
|
true /*IsLocal*/);
|
||||||
true /*IsReadOnly*/,
|
Section.setFileAddress(NewTextSectionStartAddress);
|
||||||
true /*IsLocal*/,
|
Section.setFileOffset(
|
||||||
NewTextSectionStartAddress,
|
|
||||||
getFileOffsetForAddress(NewTextSectionStartAddress));
|
getFileOffsetForAddress(NewTextSectionStartAddress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2688,55 +2680,58 @@ void RewriteInstance::mapFileSections(
|
||||||
".gcc_except_table",
|
".gcc_except_table",
|
||||||
".rodata", ".rodata.cold" };
|
".rodata", ".rodata.cold" };
|
||||||
for (auto &SectionName : Sections) {
|
for (auto &SectionName : Sections) {
|
||||||
auto SMII = EFMM->SectionMapInfo.find(SectionName);
|
auto Section = BC->getUniqueSectionByName(SectionName);
|
||||||
if (SMII == EFMM->SectionMapInfo.end())
|
if (!Section || !Section->isAllocatable() || !Section->isFinalized())
|
||||||
continue;
|
continue;
|
||||||
SectionInfo &SI = SMII->second;
|
NextAvailableAddress = alignTo(NextAvailableAddress,
|
||||||
NextAvailableAddress = alignTo(NextAvailableAddress, SI.Alignment);
|
Section->getAlignment());
|
||||||
DEBUG(dbgs() << "BOLT: mapping section " << SectionName << " (0x"
|
DEBUG(dbgs() << "BOLT: mapping section " << SectionName << " (0x"
|
||||||
<< Twine::utohexstr(SI.AllocAddress)
|
<< Twine::utohexstr(Section->getAllocAddress())
|
||||||
<< ") to 0x" << Twine::utohexstr(NextAvailableAddress)
|
<< ") to 0x" << Twine::utohexstr(NextAvailableAddress)
|
||||||
<< '\n');
|
<< '\n');
|
||||||
|
|
||||||
OLT->mapSectionAddress(ObjectsHandle,
|
OLT->mapSectionAddress(ObjectsHandle,
|
||||||
SI.SectionID,
|
Section->getSectionID(),
|
||||||
NextAvailableAddress);
|
NextAvailableAddress);
|
||||||
SI.FileAddress = NextAvailableAddress;
|
Section->setFileAddress(NextAvailableAddress);
|
||||||
SI.FileOffset = getFileOffsetForAddress(NextAvailableAddress);
|
Section->setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
|
||||||
|
|
||||||
NextAvailableAddress += SI.Size;
|
NextAvailableAddress += Section->getOutputSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling for sections with relocations.
|
// Handling for sections with relocations.
|
||||||
for (const auto &Section : BC->sections()) {
|
for (const auto &Section : BC->sections()) {
|
||||||
if (!Section.hasRelocations())
|
if (!Section ||
|
||||||
|
!Section.hasRelocations() ||
|
||||||
|
!Section.hasSectionRef())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
StringRef SectionName = Section.getName();
|
StringRef SectionName = Section.getName();
|
||||||
auto SMII = EFMM->SectionMapInfo.find(OrgSecPrefix +
|
auto OrgSection =
|
||||||
std::string(SectionName));
|
BC->getUniqueSectionByName(OrgSecPrefix + std::string(SectionName));
|
||||||
if (SMII == EFMM->SectionMapInfo.end())
|
if (!OrgSection ||
|
||||||
|
!OrgSection->isAllocatable() ||
|
||||||
|
!OrgSection->isFinalized())
|
||||||
continue;
|
continue;
|
||||||
SectionInfo &SI = SMII->second;
|
|
||||||
|
|
||||||
if (SI.FileAddress) {
|
if (OrgSection->getFileAddress()) {
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName
|
DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName
|
||||||
<< " is already mapped at 0x"
|
<< " is already mapped at 0x"
|
||||||
<< Twine::utohexstr(SI.FileAddress) << '\n');
|
<< Twine::utohexstr(OrgSection->getFileAddress()) << '\n');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DEBUG(dbgs() << "BOLT: mapping original section " << SectionName << " (0x"
|
DEBUG(dbgs() << "BOLT: mapping original section " << SectionName << " (0x"
|
||||||
<< Twine::utohexstr(SI.AllocAddress)
|
<< Twine::utohexstr(OrgSection->getAllocAddress())
|
||||||
<< ") to 0x" << Twine::utohexstr(Section.getAddress())
|
<< ") to 0x" << Twine::utohexstr(Section.getAddress())
|
||||||
<< '\n');
|
<< '\n');
|
||||||
|
|
||||||
OLT->mapSectionAddress(ObjectsHandle,
|
OLT->mapSectionAddress(ObjectsHandle,
|
||||||
SI.SectionID,
|
OrgSection->getSectionID(),
|
||||||
Section.getAddress());
|
Section.getAddress());
|
||||||
SI.FileAddress = Section.getAddress();
|
|
||||||
|
|
||||||
StringRef SectionContents = Section.getContents();
|
OrgSection->setFileAddress(Section.getAddress());
|
||||||
SI.FileOffset = SectionContents.data() - InputFile->getData().data();
|
OrgSection->setFileOffset(Section.getContents().data() -
|
||||||
|
InputFile->getData().data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2826,20 +2821,18 @@ void RewriteInstance::updateOutputValues(const MCAsmLayout &Layout) {
|
||||||
|
|
||||||
void RewriteInstance::emitDataSection(MCStreamer *Streamer,
|
void RewriteInstance::emitDataSection(MCStreamer *Streamer,
|
||||||
const BinarySection &Section,
|
const BinarySection &Section,
|
||||||
std::string Name) {
|
StringRef Name) {
|
||||||
StringRef SectionName = !Name.empty() ? StringRef(Name) : Section.getName();
|
StringRef SectionName = !Name.empty() ? Name : Section.getName();
|
||||||
const auto SectionFlags = Section.getFlags();
|
|
||||||
const auto SectionType = Section.getType();
|
|
||||||
StringRef SectionContents = Section.getContents();
|
StringRef SectionContents = Section.getContents();
|
||||||
auto *ELFSection = BC->Ctx->getELFSection(SectionName,
|
auto *ELFSection = BC->Ctx->getELFSection(SectionName,
|
||||||
SectionType,
|
Section.getELFType(),
|
||||||
SectionFlags);
|
Section.getELFFlags());
|
||||||
|
|
||||||
Streamer->SwitchSection(ELFSection);
|
Streamer->SwitchSection(ELFSection);
|
||||||
Streamer->EmitValueToAlignment(Section.getAlignment());
|
Streamer->EmitValueToAlignment(Section.getAlignment());
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: emitting "
|
DEBUG(dbgs() << "BOLT-DEBUG: emitting "
|
||||||
<< (SectionFlags & ELF::SHF_ALLOC ? "" : "non-")
|
<< (Section.isAllocatable() ? "" : "non-")
|
||||||
<< "allocatable data section " << SectionName << '\n');
|
<< "allocatable data section " << SectionName << '\n');
|
||||||
|
|
||||||
if (!Section.hasRelocations()) {
|
if (!Section.hasRelocations()) {
|
||||||
|
@ -2872,7 +2865,7 @@ void RewriteInstance::emitDataSection(MCStreamer *Streamer,
|
||||||
|
|
||||||
void RewriteInstance::emitDataSections(MCStreamer *Streamer) {
|
void RewriteInstance::emitDataSections(MCStreamer *Streamer) {
|
||||||
for (const auto &Section : BC->sections()) {
|
for (const auto &Section : BC->sections()) {
|
||||||
if (!Section.hasRelocations())
|
if (!Section || !Section.hasRelocations() || !Section.hasSectionRef())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
StringRef SectionName = Section.getName();
|
StringRef SectionName = Section.getName();
|
||||||
|
@ -2943,14 +2936,15 @@ void RewriteInstance::patchELFPHDRTable() {
|
||||||
NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum;
|
NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum;
|
||||||
NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
|
NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
|
||||||
} else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
|
} else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
|
||||||
auto SMII = EFMM->SectionMapInfo.find(".eh_frame_hdr");
|
auto EHFrameHdrSec = BC->getUniqueSectionByName(".eh_frame_hdr");
|
||||||
if (SMII != EFMM->SectionMapInfo.end()) {
|
if (EHFrameHdrSec &&
|
||||||
auto &EHFrameHdrSecInfo = SMII->second;
|
EHFrameHdrSec->isAllocatable() &&
|
||||||
NewPhdr.p_offset = EHFrameHdrSecInfo.FileOffset;
|
EHFrameHdrSec->isFinalized()) {
|
||||||
NewPhdr.p_vaddr = EHFrameHdrSecInfo.FileAddress;
|
NewPhdr.p_offset = EHFrameHdrSec->getFileOffset();
|
||||||
NewPhdr.p_paddr = EHFrameHdrSecInfo.FileAddress;
|
NewPhdr.p_vaddr = EHFrameHdrSec->getFileAddress();
|
||||||
NewPhdr.p_filesz = EHFrameHdrSecInfo.Size;
|
NewPhdr.p_paddr = EHFrameHdrSec->getFileAddress();
|
||||||
NewPhdr.p_memsz = EHFrameHdrSecInfo.Size;
|
NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize();
|
||||||
|
NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize();
|
||||||
}
|
}
|
||||||
} else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) {
|
} else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) {
|
||||||
NewPhdr.p_type = ELF::PT_LOAD;
|
NewPhdr.p_type = ELF::PT_LOAD;
|
||||||
|
@ -3053,75 +3047,79 @@ void RewriteInstance::rewriteNoteSections() {
|
||||||
Size = appendPadding(OS, Size, Section.sh_addralign);
|
Size = appendPadding(OS, Size, Section.sh_addralign);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address of extension to the section.
|
|
||||||
uint64_t Address{0};
|
|
||||||
|
|
||||||
// Perform section post-processing.
|
// Perform section post-processing.
|
||||||
auto SII = EFMM->NoteSectionInfo.find(SectionName);
|
auto BSec = BC->getUniqueSectionByName(SectionName);
|
||||||
if (SII != EFMM->NoteSectionInfo.end()) {
|
uint8_t *SectionData = nullptr;
|
||||||
auto &SI = SII->second;
|
if (BSec && !BSec->isAllocatable()) {
|
||||||
assert(SI.Alignment <= Section.sh_addralign &&
|
assert(BSec->getAlignment() <= Section.sh_addralign &&
|
||||||
"alignment exceeds value in file");
|
"alignment exceeds value in file");
|
||||||
|
|
||||||
// Write section extension.
|
if (BSec->getAllocAddress()) {
|
||||||
Address = SI.AllocAddress;
|
SectionData = BSec->getOutputData();
|
||||||
if (Address) {
|
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
|
DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
|
||||||
<< " contents to section "
|
<< " contents to section "
|
||||||
<< SectionName << '\n');
|
<< SectionName << '\n');
|
||||||
OS.write(reinterpret_cast<const char *>(Address), SI.Size);
|
OS.write(reinterpret_cast<char *>(SectionData),
|
||||||
Size += SI.Size;
|
BSec->getOutputSize());
|
||||||
|
Size += BSec->getOutputSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SI.PendingRelocs.empty()) {
|
if (BSec->hasPendingRelocations()) {
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: processing relocs for section "
|
DEBUG(dbgs() << "BOLT-DEBUG: processing relocs for section "
|
||||||
<< SectionName << '\n');
|
<< SectionName << '\n');
|
||||||
for (auto &Reloc : SI.PendingRelocs) {
|
for (auto &Reloc : BSec->pendingRelocations()) {
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: writing value "
|
DEBUG(dbgs() << "BOLT-DEBUG: writing value 0x"
|
||||||
<< Twine::utohexstr(Reloc.Value)
|
<< Twine::utohexstr(Reloc.Addend)
|
||||||
<< " of size " << (unsigned)Reloc.Size
|
<< " of size " << Relocation::getSizeForType(Reloc.Type)
|
||||||
<< " at offset "
|
<< " at offset 0x"
|
||||||
<< Twine::utohexstr(Reloc.Offset) << '\n');
|
<< Twine::utohexstr(Reloc.Offset) << '\n');
|
||||||
assert(Reloc.Size == 4 &&
|
assert(Reloc.Type == ELF::R_X86_64_32 &&
|
||||||
"only relocations of size 4 are supported at the moment");
|
"only R_X86_64_32 relocations are supported at the moment");
|
||||||
OS.pwrite(reinterpret_cast<const char*>(&Reloc.Value),
|
uint32_t Value = Reloc.Addend;
|
||||||
Reloc.Size,
|
OS.pwrite(reinterpret_cast<const char*>(&Value),
|
||||||
|
Relocation::getSizeForType(Reloc.Type),
|
||||||
NextAvailableOffset + Reloc.Offset);
|
NextAvailableOffset + Reloc.Offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set/modify section info.
|
// Set/modify section info.
|
||||||
EFMM->NoteSectionInfo[SectionName] =
|
auto &NewSection =
|
||||||
SectionInfo(Address,
|
BC->registerOrUpdateNoteSection(SectionName,
|
||||||
|
SectionData,
|
||||||
Size,
|
Size,
|
||||||
Section.sh_addralign,
|
Section.sh_addralign,
|
||||||
/*IsCode=*/false,
|
BSec ? BSec->isReadOnly() : false,
|
||||||
/*IsReadOnly=*/false,
|
BSec ? BSec->getELFType()
|
||||||
/*IsLocal=*/false,
|
: ELF::SHT_PROGBITS,
|
||||||
/*FileAddress=*/0,
|
BSec ? BSec->isLocal() : false);
|
||||||
NextAvailableOffset);
|
NewSection.setFileAddress(0);
|
||||||
|
NewSection.setFileOffset(NextAvailableOffset);
|
||||||
|
|
||||||
NextAvailableOffset += Size;
|
NextAvailableOffset += Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write new note sections.
|
// Write new note sections.
|
||||||
for (auto &SII : EFMM->NoteSectionInfo) {
|
for (auto &Section : BC->sections()) {
|
||||||
auto &SI = SII.second;
|
if (!Section ||
|
||||||
if (SI.FileOffset || !SI.AllocAddress)
|
Section.getFileOffset() ||
|
||||||
|
!Section.getAllocAddress() ||
|
||||||
|
Section.isAllocatable())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
assert(SI.PendingRelocs.empty() && "cannot have pending relocs");
|
assert(!Section.hasPendingRelocations() && "cannot have pending relocs");
|
||||||
|
|
||||||
NextAvailableOffset = appendPadding(OS, NextAvailableOffset, SI.Alignment);
|
NextAvailableOffset = appendPadding(OS, NextAvailableOffset,
|
||||||
SI.FileOffset = NextAvailableOffset;
|
Section.getAlignment());
|
||||||
|
Section.setFileOffset(NextAvailableOffset);
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: writing out new section " << SII.first
|
DEBUG(dbgs() << "BOLT-DEBUG: writing out new section "
|
||||||
<< " of size " << SI.Size << " at offset 0x"
|
<< Section.getName() << " of size " << Section.getOutputSize()
|
||||||
<< Twine::utohexstr(SI.FileOffset) << '\n');
|
<< " at offset 0x" << Twine::utohexstr(Section.getFileOffset())
|
||||||
|
<< '\n');
|
||||||
|
|
||||||
OS.write(reinterpret_cast<const char *>(SI.AllocAddress), SI.Size);
|
OS.write(Section.getOutputContents().data(), Section.getOutputSize());
|
||||||
NextAvailableOffset += SI.Size;
|
NextAvailableOffset += Section.getOutputSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3140,11 +3138,10 @@ void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
|
||||||
SHStrTab.add(*AllSHStrTabStrings.back());
|
SHStrTab.add(*AllSHStrTabStrings.back());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto &SMII : EFMM->SectionMapInfo) {
|
for (auto &Section : BC->sections()) {
|
||||||
SHStrTab.add(SMII.first);
|
if (Section) {
|
||||||
|
SHStrTab.add(Section.getName());
|
||||||
}
|
}
|
||||||
for (auto &SMII : EFMM->NoteSectionInfo) {
|
|
||||||
SHStrTab.add(SMII.first);
|
|
||||||
}
|
}
|
||||||
SHStrTab.finalize();
|
SHStrTab.finalize();
|
||||||
|
|
||||||
|
@ -3152,14 +3149,12 @@ void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
|
||||||
uint8_t *DataCopy = new uint8_t[SHStrTabSize];
|
uint8_t *DataCopy = new uint8_t[SHStrTabSize];
|
||||||
memset(DataCopy, 0, SHStrTabSize);
|
memset(DataCopy, 0, SHStrTabSize);
|
||||||
SHStrTab.write(DataCopy);
|
SHStrTab.write(DataCopy);
|
||||||
EFMM->NoteSectionInfo[".shstrtab"] =
|
BC->registerOrUpdateNoteSection(".shstrtab",
|
||||||
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
|
DataCopy,
|
||||||
SHStrTabSize,
|
SHStrTabSize,
|
||||||
/*Alignment*/1,
|
/*Alignment=*/1,
|
||||||
/*IsCode=*/false,
|
/*IsReadOnly=*/true,
|
||||||
/*IsReadOnly=*/false,
|
ELF::SHT_STRTAB);
|
||||||
/*IsLocal=*/false);
|
|
||||||
EFMM->NoteSectionInfo[".shstrtab"].IsStrTab = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RewriteInstance::addBoltInfoSection() {
|
void RewriteInstance::addBoltInfoSection() {
|
||||||
|
@ -3194,16 +3189,12 @@ void RewriteInstance::addBoltInfoSection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto BoltInfo = OS.str();
|
const auto BoltInfo = OS.str();
|
||||||
const auto SectionSize = BoltInfo.size();
|
BC->registerOrUpdateNoteSection(".note.bolt_info",
|
||||||
uint8_t *SectionData = new uint8_t[SectionSize];
|
copyByteArray(BoltInfo),
|
||||||
memcpy(SectionData, BoltInfo.data(), SectionSize);
|
BoltInfo.size(),
|
||||||
EFMM->NoteSectionInfo[".note.bolt_info"] =
|
|
||||||
SectionInfo(reinterpret_cast<uint64_t>(SectionData), SectionSize,
|
|
||||||
/*Alignment=*/1,
|
/*Alignment=*/1,
|
||||||
/*IsCode=*/false,
|
|
||||||
/*IsReadOnly=*/true,
|
/*IsReadOnly=*/true,
|
||||||
/*IsLocal=*/false, 0, 0, 0,
|
ELF::SHT_NOTE);
|
||||||
/*IsELFNote=*/true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3275,20 +3266,21 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are creating our own .text section, it should be the first section
|
// If we are creating our own .text section, it should be the first section
|
||||||
// we created in EFMM->SectionMapInfo, so this is the correct index.
|
// we created in BinaryContext, so this is the correct index.
|
||||||
if (!opts::UseOldText) {
|
if (!opts::UseOldText) {
|
||||||
NewTextSectionIndex = CurIndex;
|
NewTextSectionIndex = CurIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process entries for all new allocatable sections.
|
// Process entries for all new allocatable sections.
|
||||||
for (auto &SMII : EFMM->SectionMapInfo) {
|
for (auto &Section : BC->sections()) {
|
||||||
const auto &SectionName = SMII.first;
|
if (!Section || !Section.isAllocatable() || !Section.isFinalized())
|
||||||
const auto &SI = SMII.second;
|
continue;
|
||||||
|
|
||||||
// Ignore function sections.
|
// Ignore function sections.
|
||||||
if (SI.FileAddress < NewTextSegmentAddress) {
|
if (Section.getFileAddress() < NewTextSegmentAddress) {
|
||||||
if (opts::Verbosity)
|
if (opts::Verbosity)
|
||||||
outs() << "BOLT-INFO: not writing section header for existing section "
|
outs() << "BOLT-INFO: not writing section header for existing section "
|
||||||
<< SMII.first << '\n';
|
<< Section.getName() << '\n';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3298,18 +3290,19 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (opts::Verbosity >= 1)
|
if (opts::Verbosity >= 1)
|
||||||
outs() << "BOLT-INFO: writing section header for " << SectionName << '\n';
|
outs() << "BOLT-INFO: writing section header for "
|
||||||
|
<< Section.getName() << '\n';
|
||||||
ELFShdrTy NewSection;
|
ELFShdrTy NewSection;
|
||||||
NewSection.sh_name = SHStrTab.getOffset(SectionName);
|
NewSection.sh_name = SHStrTab.getOffset(Section.getName());
|
||||||
NewSection.sh_type = ELF::SHT_PROGBITS;
|
NewSection.sh_type = ELF::SHT_PROGBITS;
|
||||||
NewSection.sh_addr = SI.FileAddress;
|
NewSection.sh_addr = Section.getFileAddress();
|
||||||
NewSection.sh_offset = SI.FileOffset;
|
NewSection.sh_offset = Section.getFileOffset();
|
||||||
NewSection.sh_size = SI.Size;
|
NewSection.sh_size = Section.getOutputSize();
|
||||||
NewSection.sh_entsize = 0;
|
NewSection.sh_entsize = 0;
|
||||||
NewSection.sh_flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
|
NewSection.sh_flags = Section.getELFFlags();
|
||||||
NewSection.sh_link = 0;
|
NewSection.sh_link = 0;
|
||||||
NewSection.sh_info = 0;
|
NewSection.sh_info = 0;
|
||||||
NewSection.sh_addralign = SI.Alignment;
|
NewSection.sh_addralign = Section.getAlignment();
|
||||||
OutputSections->emplace_back(NewSection);
|
OutputSections->emplace_back(NewSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3336,19 +3329,17 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
|
||||||
StringRef SectionName =
|
StringRef SectionName =
|
||||||
cantFail(Obj->getSectionName(&Section), "cannot get section name");
|
cantFail(Obj->getSectionName(&Section), "cannot get section name");
|
||||||
|
|
||||||
auto SII = EFMM->NoteSectionInfo.find(SectionName);
|
auto BSec = BC->getUniqueSectionByName(SectionName);
|
||||||
assert(SII != EFMM->NoteSectionInfo.end() &&
|
assert(BSec && "missing section info for non-allocatable section");
|
||||||
"missing section info for non-allocatable section");
|
|
||||||
|
|
||||||
const auto &SI = SII->second;
|
|
||||||
auto NewSection = Section;
|
auto NewSection = Section;
|
||||||
NewSection.sh_offset = SI.FileOffset;
|
NewSection.sh_offset = BSec->getFileOffset();
|
||||||
NewSection.sh_size = SI.Size;
|
NewSection.sh_size = BSec->getOutputSize();
|
||||||
NewSection.sh_name = SHStrTab.getOffset(SectionName);
|
NewSection.sh_name = SHStrTab.getOffset(SectionName);
|
||||||
|
|
||||||
OutputSections->emplace_back(NewSection);
|
OutputSections->emplace_back(NewSection);
|
||||||
|
|
||||||
LastFileOffset = SI.FileOffset;
|
LastFileOffset = BSec->getFileOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map input -> output is ready. Early return if that's all we need.
|
// Map input -> output is ready. Early return if that's all we need.
|
||||||
|
@ -3356,28 +3347,27 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
|
||||||
return NewSectionIndex;
|
return NewSectionIndex;
|
||||||
|
|
||||||
// Create entries for new non-allocatable sections.
|
// Create entries for new non-allocatable sections.
|
||||||
for (auto &SII : EFMM->NoteSectionInfo) {
|
for (auto &Section : BC->sections()) {
|
||||||
const auto &SectionName = SII.first;
|
if (!Section ||
|
||||||
const auto &SI = SII.second;
|
Section.isAllocatable() ||
|
||||||
|
Section.getFileOffset() <= LastFileOffset)
|
||||||
if (SI.FileOffset <= LastFileOffset)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (opts::Verbosity >= 1)
|
if (opts::Verbosity >= 1) {
|
||||||
outs() << "BOLT-INFO: writing section header for " << SectionName << '\n';
|
outs() << "BOLT-INFO: writing section header for "
|
||||||
|
<< Section.getName() << '\n';
|
||||||
|
}
|
||||||
ELFShdrTy NewSection;
|
ELFShdrTy NewSection;
|
||||||
NewSection.sh_name = SHStrTab.getOffset(SectionName);
|
NewSection.sh_name = SHStrTab.getOffset(Section.getName());
|
||||||
NewSection.sh_type =
|
NewSection.sh_type = Section.getELFType();
|
||||||
(SI.IsStrTab ? ELF::SHT_STRTAB
|
|
||||||
: SI.IsELFNote ? ELF::SHT_NOTE : ELF::SHT_PROGBITS);
|
|
||||||
NewSection.sh_addr = 0;
|
NewSection.sh_addr = 0;
|
||||||
NewSection.sh_offset = SI.FileOffset;
|
NewSection.sh_offset = Section.getFileOffset();
|
||||||
NewSection.sh_size = SI.Size;
|
NewSection.sh_size = Section.getOutputSize();
|
||||||
NewSection.sh_entsize = 0;
|
NewSection.sh_entsize = 0;
|
||||||
NewSection.sh_flags = 0;
|
NewSection.sh_flags = Section.getELFFlags();
|
||||||
NewSection.sh_link = 0;
|
NewSection.sh_link = 0;
|
||||||
NewSection.sh_info = 0;
|
NewSection.sh_info = 0;
|
||||||
NewSection.sh_addralign = SI.Alignment ? SI.Alignment : 1;
|
NewSection.sh_addralign = Section.getAlignment();
|
||||||
OutputSections->emplace_back(NewSection);
|
OutputSections->emplace_back(NewSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3660,23 +3650,19 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
|
||||||
return Idx;
|
return Idx;
|
||||||
});
|
});
|
||||||
|
|
||||||
uint8_t *DataCopy = new uint8_t[NewContents.size()];
|
BC->registerOrUpdateNoteSection(SecName,
|
||||||
memcpy(DataCopy, NewContents.data(), NewContents.size());
|
copyByteArray(NewContents),
|
||||||
EFMM->NoteSectionInfo[SecName] =
|
NewContents.size(),
|
||||||
SectionInfo(reinterpret_cast<uint64_t>(DataCopy), NewContents.size(),
|
/*Alignment=*/1,
|
||||||
/*Alignment*/ 1,
|
/*IsReadOnly=*/true,
|
||||||
/*IsCode=*/false,
|
ELF::SHT_SYMTAB);
|
||||||
/*IsReadOnly=*/false,
|
|
||||||
/*IsLocal=*/false);
|
BC->registerOrUpdateNoteSection(StrSecName,
|
||||||
DataCopy = new uint8_t[NewStrTab.size()];
|
copyByteArray(NewStrTab),
|
||||||
memcpy(DataCopy, NewStrTab.data(), NewStrTab.size());
|
NewStrTab.size(),
|
||||||
EFMM->NoteSectionInfo[StrSecName] =
|
/*Alignment=*/1,
|
||||||
SectionInfo(reinterpret_cast<uint64_t>(DataCopy), NewStrTab.size(),
|
/*IsReadOnly=*/true,
|
||||||
/*Alignment*/ 1,
|
ELF::SHT_STRTAB);
|
||||||
/*IsCode=*/false,
|
|
||||||
/*IsReadOnly=*/false,
|
|
||||||
/*IsLocal=*/false);
|
|
||||||
EFMM->NoteSectionInfo[StrSecName].IsStrTab = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ELFT>
|
template <typename ELFT>
|
||||||
|
@ -3892,13 +3878,12 @@ void RewriteInstance::rewriteFile() {
|
||||||
if (opts::JumpTables == JTS_BASIC) {
|
if (opts::JumpTables == JTS_BASIC) {
|
||||||
for (auto &JTI : Function.JumpTables) {
|
for (auto &JTI : Function.JumpTables) {
|
||||||
auto &JT = JTI.second;
|
auto &JT = JTI.second;
|
||||||
assert(JT.SecInfo && "section info for jump table expected");
|
assert(JT.Section && "section for jump table expected");
|
||||||
JT.SecInfo->FileOffset =
|
JT.Section->setFileOffset(getFileOffsetForAddress(JT.Address));
|
||||||
getFileOffsetForAddress(JT.Address);
|
assert(JT.Section->getFileOffset() && "no matching offset in file");
|
||||||
assert(JT.SecInfo->FileOffset && "no matching offset in file");
|
OS.pwrite(reinterpret_cast<const char*>(JT.Section->getOutputData()),
|
||||||
Out->os().pwrite(reinterpret_cast<char *>(JT.SecInfo->AllocAddress),
|
JT.Section->getOutputSize(),
|
||||||
JT.SecInfo->Size,
|
JT.Section->getFileOffset());
|
||||||
JT.SecInfo->FileOffset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3959,27 +3944,26 @@ void RewriteInstance::rewriteFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all non-local sections, i.e. those not emitted with the function.
|
// Write all non-local sections, i.e. those not emitted with the function.
|
||||||
for (auto &SMII : EFMM->SectionMapInfo) {
|
for (auto &Section : BC->sections()) {
|
||||||
SectionInfo &SI = SMII.second;
|
if (!Section ||
|
||||||
if (SI.IsLocal)
|
!Section.isAllocatable() ||
|
||||||
|
!Section.isFinalized() ||
|
||||||
|
Section.isLocal())
|
||||||
continue;
|
continue;
|
||||||
if (opts::Verbosity >= 1) {
|
if (opts::Verbosity >= 1) {
|
||||||
outs() << "BOLT: writing new section " << SMII.first << '\n';
|
outs() << "BOLT: writing new section " << Section.getName() << '\n';
|
||||||
outs() << " data at 0x" << Twine::utohexstr(SI.AllocAddress) << '\n';
|
outs() << " data at 0x" << Twine::utohexstr(Section.getAllocAddress()) << '\n';
|
||||||
outs() << " of size " << SI.Size << '\n';
|
outs() << " of size " << Section.getOutputSize() << '\n';
|
||||||
outs() << " at offset " << SI.FileOffset << '\n';
|
outs() << " at offset " << Section.getFileOffset() << '\n';
|
||||||
}
|
}
|
||||||
OS.pwrite(reinterpret_cast<const char *>(SI.AllocAddress),
|
OS.pwrite(reinterpret_cast<const char*>(Section.getOutputData()),
|
||||||
SI.Size,
|
Section.getOutputSize(),
|
||||||
SI.FileOffset);
|
Section.getFileOffset());
|
||||||
assert(SI.AllocAddress &&
|
|
||||||
"writing section that was not assigned an address");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If .eh_frame is present create .eh_frame_hdr.
|
// If .eh_frame is present create .eh_frame_hdr.
|
||||||
auto SMII = EFMM->SectionMapInfo.find(".eh_frame");
|
if (EHFrameSection && EHFrameSection->isFinalized()) {
|
||||||
if (SMII != EFMM->SectionMapInfo.end()) {
|
writeEHFrameHeader();
|
||||||
writeEHFrameHeader(SMII->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch program header table.
|
// Patch program header table.
|
||||||
|
@ -4006,6 +3990,11 @@ void RewriteInstance::rewriteFile() {
|
||||||
// Update ELF book-keeping info.
|
// Update ELF book-keeping info.
|
||||||
patchELFSectionHeaderTable();
|
patchELFSectionHeaderTable();
|
||||||
|
|
||||||
|
if (opts::PrintSections) {
|
||||||
|
outs() << "BOLT-INFO: Sections after processing:\n";
|
||||||
|
BC->printSections(outs());
|
||||||
|
}
|
||||||
|
|
||||||
Out->keep();
|
Out->keep();
|
||||||
|
|
||||||
// If requested, open again the binary we just wrote to dump its EH Frame
|
// If requested, open again the binary we just wrote to dump its EH Frame
|
||||||
|
@ -4025,54 +4014,69 @@ void RewriteInstance::rewriteFile() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RewriteInstance::writeEHFrameHeader(SectionInfo &EHFrameSecInfo) {
|
void RewriteInstance::writeEHFrameHeader() {
|
||||||
DWARFDebugFrame NewEHFrame(true, EHFrameSecInfo.FileAddress);
|
DWARFDebugFrame NewEHFrame(true, EHFrameSection->getFileAddress());
|
||||||
NewEHFrame.parse(DWARFDataExtractor(
|
NewEHFrame.parse(DWARFDataExtractor(EHFrameSection->getOutputContents(),
|
||||||
StringRef(reinterpret_cast<const char *>(EHFrameSecInfo.AllocAddress),
|
BC->AsmInfo->isLittleEndian(),
|
||||||
EHFrameSecInfo.Size),
|
BC->AsmInfo->getCodePointerSize()));
|
||||||
BC->AsmInfo->isLittleEndian(), BC->AsmInfo->getCodePointerSize()));
|
|
||||||
|
|
||||||
auto OldSMII = EFMM->SectionMapInfo.find(".eh_frame_old");
|
auto OldEHFrameSection = BC->getUniqueSectionByName(".eh_frame_old");
|
||||||
assert(OldSMII != EFMM->SectionMapInfo.end() &&
|
assert(OldEHFrameSection && "expected .eh_frame_old to be present");
|
||||||
"expected .eh_frame_old to be present");
|
DWARFDebugFrame OldEHFrame(true, OldEHFrameSection->getFileAddress());
|
||||||
auto &OldEHFrameSecInfo = OldSMII->second;
|
OldEHFrame.parse(DWARFDataExtractor(OldEHFrameSection->getOutputContents(),
|
||||||
DWARFDebugFrame OldEHFrame(true, OldEHFrameSecInfo.FileAddress);
|
BC->AsmInfo->isLittleEndian(),
|
||||||
OldEHFrame.parse(DWARFDataExtractor(
|
BC->AsmInfo->getCodePointerSize()));
|
||||||
StringRef(reinterpret_cast<const char *>(OldEHFrameSecInfo.AllocAddress),
|
|
||||||
OldEHFrameSecInfo.Size),
|
|
||||||
BC->AsmInfo->isLittleEndian(), BC->AsmInfo->getCodePointerSize()));
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n");
|
DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n");
|
||||||
|
|
||||||
NextAvailableAddress =
|
NextAvailableAddress =
|
||||||
appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
|
appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
|
||||||
|
|
||||||
SectionInfo EHFrameHdrSecInfo;
|
const auto EHFrameHdrFileAddress = NextAvailableAddress;
|
||||||
EHFrameHdrSecInfo.FileAddress = NextAvailableAddress;
|
const auto EHFrameHdrFileOffset =
|
||||||
EHFrameHdrSecInfo.FileOffset = getFileOffsetForAddress(NextAvailableAddress);
|
getFileOffsetForAddress(NextAvailableAddress);
|
||||||
|
|
||||||
auto NewEHFrameHdr =
|
auto NewEHFrameHdr =
|
||||||
CFIRdWrt->generateEHFrameHeader(OldEHFrame,
|
CFIRdWrt->generateEHFrameHeader(OldEHFrame,
|
||||||
NewEHFrame,
|
NewEHFrame,
|
||||||
EHFrameHdrSecInfo.FileAddress,
|
EHFrameHdrFileAddress,
|
||||||
FailedAddresses);
|
FailedAddresses);
|
||||||
|
|
||||||
EHFrameHdrSecInfo.Size = NewEHFrameHdr.size();
|
assert(Out->os().tell() == EHFrameHdrFileOffset && "offset mismatch");
|
||||||
|
Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size());
|
||||||
|
|
||||||
assert(Out->os().tell() == EHFrameHdrSecInfo.FileOffset &&
|
const auto Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
|
||||||
"offset mismatch");
|
/*IsText=*/false,
|
||||||
Out->os().write(NewEHFrameHdr.data(), EHFrameHdrSecInfo.Size);
|
/*IsAllocatable=*/true);
|
||||||
|
auto &EHFrameHdrSec = BC->registerOrUpdateSection(".eh_frame_hdr",
|
||||||
|
ELF::SHT_PROGBITS,
|
||||||
|
Flags,
|
||||||
|
nullptr,
|
||||||
|
NewEHFrameHdr.size(),
|
||||||
|
/*Alignment=*/1);
|
||||||
|
EHFrameHdrSec.setFileOffset(EHFrameHdrFileOffset);
|
||||||
|
EHFrameHdrSec.setFileAddress(EHFrameHdrFileAddress);
|
||||||
|
|
||||||
EFMM->SectionMapInfo[".eh_frame_hdr"] = EHFrameHdrSecInfo;
|
NextAvailableAddress += EHFrameHdrSec.getOutputSize();
|
||||||
|
|
||||||
NextAvailableAddress += EHFrameHdrSecInfo.Size;
|
|
||||||
|
|
||||||
// Merge .eh_frame and .eh_frame_old so that gdb can locate all FDEs.
|
// Merge .eh_frame and .eh_frame_old so that gdb can locate all FDEs.
|
||||||
EHFrameSecInfo.Size = OldEHFrameSecInfo.FileAddress + OldEHFrameSecInfo.Size
|
const auto EHFrameSectionSize = (OldEHFrameSection->getFileAddress() +
|
||||||
- EHFrameSecInfo.FileAddress;
|
OldEHFrameSection->getOutputSize() -
|
||||||
EFMM->SectionMapInfo.erase(OldSMII);
|
EHFrameSection->getFileAddress());
|
||||||
|
|
||||||
|
EHFrameSection =
|
||||||
|
BC->registerOrUpdateSection(".eh_frame",
|
||||||
|
EHFrameSection->getELFType(),
|
||||||
|
EHFrameSection->getELFFlags(),
|
||||||
|
EHFrameSection->getOutputData(),
|
||||||
|
EHFrameSectionSize,
|
||||||
|
EHFrameSection->getAlignment(),
|
||||||
|
EHFrameSection->isLocal());
|
||||||
|
|
||||||
|
BC->deregisterSection(*OldEHFrameSection);
|
||||||
|
|
||||||
DEBUG(dbgs() << "BOLT-DEBUG: size of .eh_frame after merge is "
|
DEBUG(dbgs() << "BOLT-DEBUG: size of .eh_frame after merge is "
|
||||||
<< EHFrameSecInfo.Size << '\n');
|
<< EHFrameSection->getOutputSize() << '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const {
|
uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const {
|
||||||
|
@ -4100,11 +4104,8 @@ bool RewriteInstance::willOverwriteSection(StringRef SectionName) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMII = EFMM->SectionMapInfo.find(SectionName);
|
auto Section = BC->getUniqueSectionByName(SectionName);
|
||||||
if (SMII != EFMM->SectionMapInfo.end())
|
return Section && Section->isAllocatable() && Section->isFinalized();
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryFunction *
|
BinaryFunction *
|
||||||
|
|
|
@ -39,43 +39,6 @@ class CFIReaderWriter;
|
||||||
class DataAggregator;
|
class DataAggregator;
|
||||||
class DataReader;
|
class DataReader;
|
||||||
|
|
||||||
/// Section information for mapping and re-writing.
|
|
||||||
struct SectionInfo {
|
|
||||||
uint64_t AllocAddress{0}; /// Current location of the section in memory.
|
|
||||||
uint64_t Size{0}; /// Section size.
|
|
||||||
unsigned Alignment{0}; /// Alignment of the section.
|
|
||||||
bool IsCode{false}; /// Does this section contain code?
|
|
||||||
bool IsReadOnly{false}; /// Is the section read-only?
|
|
||||||
bool IsLocal{false}; /// Is this section local to a function, and
|
|
||||||
/// should only be emitted with the function?
|
|
||||||
bool IsStrTab{false}; /// Is this a string table section.
|
|
||||||
uint64_t FileAddress{0}; /// Address for the output file (final address).
|
|
||||||
uint64_t FileOffset{0}; /// Offset in the output file.
|
|
||||||
unsigned SectionID{0}; /// Unique ID used for address mapping.
|
|
||||||
bool IsELFNote{false}; /// Is ELF note section?
|
|
||||||
|
|
||||||
struct Reloc {
|
|
||||||
uint32_t Offset;
|
|
||||||
uint8_t Size;
|
|
||||||
uint8_t Type; // unused atm
|
|
||||||
uint32_t Value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Pending relocations for the section.
|
|
||||||
std::vector<Reloc> PendingRelocs;
|
|
||||||
|
|
||||||
SectionInfo(uint64_t Address, uint64_t Size, unsigned Alignment, bool IsCode,
|
|
||||||
bool IsReadOnly, bool IsLocal, uint64_t FileAddress = 0,
|
|
||||||
uint64_t FileOffset = 0, unsigned SectionID = 0,
|
|
||||||
bool IsELFNote = false)
|
|
||||||
|
|
||||||
: AllocAddress(Address), Size(Size), Alignment(Alignment), IsCode(IsCode),
|
|
||||||
IsReadOnly(IsReadOnly), IsLocal(IsLocal), FileAddress(FileAddress),
|
|
||||||
FileOffset(FileOffset), SectionID(SectionID), IsELFNote(IsELFNote) {}
|
|
||||||
|
|
||||||
SectionInfo() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentInfo {
|
struct SegmentInfo {
|
||||||
uint64_t Address; /// Address of the segment in memory.
|
uint64_t Address; /// Address of the segment in memory.
|
||||||
uint64_t Size; /// Size of the segment in memory.
|
uint64_t Size; /// Size of the segment in memory.
|
||||||
|
@ -105,20 +68,15 @@ private:
|
||||||
StringRef SectionName,
|
StringRef SectionName,
|
||||||
bool IsCode,
|
bool IsCode,
|
||||||
bool IsReadOnly);
|
bool IsReadOnly);
|
||||||
|
BinaryContext &BC;
|
||||||
bool AllowStubs;
|
bool AllowStubs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// [start memory address] -> [segment info] mapping.
|
/// [start memory address] -> [segment info] mapping.
|
||||||
std::map<uint64_t, SegmentInfo> SegmentMapInfo;
|
std::map<uint64_t, SegmentInfo> SegmentMapInfo;
|
||||||
|
|
||||||
/// Keep [section name] -> [section info] map for later remapping.
|
ExecutableFileMemoryManager(BinaryContext &BC, bool AllowStubs)
|
||||||
std::map<std::string, SectionInfo> SectionMapInfo;
|
: BC(BC), AllowStubs(AllowStubs) {}
|
||||||
|
|
||||||
/// Information about non-allocatable sections.
|
|
||||||
std::map<std::string, SectionInfo> NoteSectionInfo;
|
|
||||||
|
|
||||||
ExecutableFileMemoryManager(bool AllowStubs) : AllowStubs(AllowStubs) {}
|
|
||||||
|
|
||||||
~ExecutableFileMemoryManager();
|
~ExecutableFileMemoryManager();
|
||||||
|
|
||||||
|
@ -202,7 +160,7 @@ public:
|
||||||
/// non-empty.
|
/// non-empty.
|
||||||
void emitDataSection(MCStreamer *Streamer,
|
void emitDataSection(MCStreamer *Streamer,
|
||||||
const BinarySection &Section,
|
const BinarySection &Section,
|
||||||
std::string Name = "");
|
StringRef Name = StringRef());
|
||||||
|
|
||||||
/// Emit data sections that have code references in them.
|
/// Emit data sections that have code references in them.
|
||||||
void emitDataSections(MCStreamer *Streamer);
|
void emitDataSections(MCStreamer *Streamer);
|
||||||
|
@ -312,7 +270,7 @@ private:
|
||||||
void rewriteNoteSections();
|
void rewriteNoteSections();
|
||||||
|
|
||||||
/// Write .eh_frame_hdr.
|
/// Write .eh_frame_hdr.
|
||||||
void writeEHFrameHeader(SectionInfo &EHFrameSecInfo);
|
void writeEHFrameHeader();
|
||||||
|
|
||||||
/// Disassemble and create function entries for PLT.
|
/// Disassemble and create function entries for PLT.
|
||||||
void disassemblePLT();
|
void disassemblePLT();
|
||||||
|
|
Loading…
Reference in New Issue