[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:
Bill Nell 2018-02-01 16:33:43 -08:00 committed by Maksim Panchenko
parent 6744f0dbeb
commit ddefc770b0
9 changed files with 860 additions and 527 deletions

View File

@ -23,6 +23,9 @@
using namespace llvm;
using namespace bolt;
#undef DEBUG_TYPE
#define DEBUG_TYPE "bolt"
namespace opts {
extern cl::OptionCategory BoltCategory;
@ -31,23 +34,30 @@ static cl::opt<bool>
PrintDebugInfo("print-debug-info",
cl::desc("print debug info when printing functions"),
cl::Hidden,
cl::ZeroOrMore,
cl::cat(BoltCategory));
static cl::opt<bool>
cl::opt<bool>
PrintRelocations("print-relocations",
cl::desc("print relocations when printing functions"),
cl::desc("print relocations when printing functions/objects"),
cl::Hidden,
cl::ZeroOrMore,
cl::cat(BoltCategory));
static cl::opt<bool>
PrintMemData("print-mem-data",
cl::desc("print memory data annotations when printing functions"),
cl::Hidden,
cl::ZeroOrMore,
cl::cat(BoltCategory));
} // namespace opts
BinaryContext::~BinaryContext() { }
BinaryContext::~BinaryContext() {
for (auto *Section : Sections) {
delete Section;
}
}
std::unique_ptr<MCObjectWriter>
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);
}
BinarySection &BinaryContext::registerSection(SectionRef Section) {
StringRef Name;
Section.getName(Name);
auto Res = Sections.insert(BinarySection(Section));
BinarySection &BinaryContext::registerSection(BinarySection *Section) {
assert(!Section->getName().empty() &&
"can't register sections without a name");
auto Res = Sections.insert(Section);
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.
if (Section.getAddress())
AddressToSection.insert(std::make_pair(Section.getAddress(), BS));
NameToSection.insert(std::make_pair(Name, BS));
return *BS;
if (Section->getAddress())
AddressToSection.insert(std::make_pair(Section->getAddress(), Section));
NameToSection.insert(std::make_pair(Section->getName(), Section));
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>
@ -504,27 +576,24 @@ BinaryContext::extractPointerAtAddress(uint64_t Address) const {
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,
MCSymbol *Symbol,
uint64_t Type,
uint64_t Addend) {
uint64_t Addend,
uint64_t Value) {
auto Section = getSectionForAddress(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);
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) {

View File

@ -16,6 +16,7 @@
#include "BinarySection.h"
#include "DebugData.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@ -58,9 +59,17 @@ class BinaryContext {
BinaryContext() = delete;
/// 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;
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
/// section mapped to the same address, e.g. non-allocatable sections.
using AddressToSectionMapType = std::multimap<uint64_t, BinarySection *>;
@ -70,6 +79,9 @@ class BinaryContext {
/// have multiple sections with the same name.
using NameToSectionMapType = std::multimap<std::string, BinarySection *>;
NameToSectionMapType NameToSection;
/// Low level section registration.
BinarySection &registerSection(BinarySection *Section);
public:
/// [name] -> [address] map used for global symbol resolution.
@ -125,8 +137,6 @@ public:
std::unique_ptr<MCAsmBackend> MAB;
std::function<void(std::error_code)> ErrorCheck;
DataReader &DR;
/// Indicates if relocations are availabe for usage.
@ -224,18 +234,53 @@ public:
ErrorOr<ArrayRef<uint8_t>>
getFunctionData(const BinaryFunction &Function) const;
/// Register information about the given section so we can look up
/// sections for addresses.
/// Register information about the given \p Section so we can look up
/// sections by address.
BinarySection &registerSection(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 &registerOrUpdateSection(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 &registerOrUpdateNoteSection(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());
}
iterator_range<SectionSetType::const_iterator> sections() const {
/// Iterate over all registered sections.
iterator_range<SectionConstIterator> sections() const {
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
/// functions only work for allocatable sections, i.e. ones with non-zero
/// addresses.
@ -305,17 +350,12 @@ public:
BinaryFunction &ParentBF,
std::map<uint64_t, BinaryFunction> &BFs);
/// Add relocation for \p Section at a given \p Offset.
void addSectionRelocation(BinarySection &Section, uint64_t Offset,
MCSymbol *Symbol, uint64_t Type,
uint64_t Addend = 0);
/// Add a relocation at a given \p Address.
/// Add a Section relocation at a given \p Address.
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.
void removeRelocationAt(uint64_t Address);
bool removeRelocationAt(uint64_t Address);
/// Return a relocation registered at a given \p Address, or nullptr if there
/// is no relocation at such address.

View File

@ -1312,8 +1312,18 @@ void BinaryFunction::postProcessJumpTables() {
TakenBranches.emplace_back(JTSiteOffset, TargetOffset);
// Take ownership of jump table relocations.
if (BC.HasRelocations)
BC.removeRelocationAt(JT->Address + EntryOffset);
if (BC.HasRelocations) {
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;
@ -3363,7 +3373,7 @@ void BinaryFunction::JumpTable::updateOriginal(BinaryContext &BC) {
<< " at offset " << Twine::utohexstr(Offset) << " for symbol "
<< Entry->getName() << " with addend "
<< Twine::utohexstr(RelAddend) << '\n');
BC.addSectionRelocation(*Section, Offset, Entry, RelType, RelAddend);
Section->addRelocation(Offset, Entry, RelType, RelAddend);
Offset += EntrySize;
}
}

View File

@ -24,6 +24,7 @@
#include "DebugData.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/iterator.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
@ -600,7 +601,7 @@ public:
std::map<unsigned, MCSymbol *> Labels;
/// Corresponding section if any.
SectionInfo *SecInfo{nullptr};
ErrorOr<BinarySection &> Section{std::errc::bad_address};
/// Corresponding section name if any.
std::string SectionName;
@ -747,21 +748,6 @@ private:
/// Count the number of functions created.
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.
void addAlternativeName(std::string NewName) {
Names.emplace_back(NewName);
@ -842,13 +828,12 @@ public:
BinaryFunction(BinaryFunction &&) = default;
typedef Iterator<BasicBlockListType::iterator, BinaryBasicBlock> iterator;
typedef Iterator<BasicBlockListType::const_iterator,
const BinaryBasicBlock> const_iterator;
typedef Iterator<BasicBlockListType::reverse_iterator,
BinaryBasicBlock> reverse_iterator;
typedef Iterator<BasicBlockListType::const_reverse_iterator,
const BinaryBasicBlock> const_reverse_iterator;
using iterator = pointee_iterator<BasicBlockListType::iterator>;
using const_iterator = pointee_iterator<BasicBlockListType::const_iterator>;
using reverse_iterator =
pointee_iterator<BasicBlockListType::reverse_iterator>;
using const_reverse_iterator =
pointee_iterator<BasicBlockListType::const_reverse_iterator>;
typedef BasicBlockOrderType::iterator order_iterator;
typedef BasicBlockOrderType::const_iterator const_order_iterator;

View File

@ -12,10 +12,18 @@
#include "BinarySection.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/CommandLine.h"
#undef DEBUG_TYPE
#define DEBUG_TYPE "bolt"
using namespace llvm;
using namespace bolt;
namespace opts {
extern cl::opt<bool> PrintRelocations;
}
Triple::ArchType Relocation::Arch;
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(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;
}
}

View File

@ -1,4 +1,4 @@
//===--- BinarySection.h - Interface for object file section -------------===//
//===--- BinarySection.h - Interface for object file section --------------===//
//
// The LLVM Compiler Infrastructure
//
@ -12,6 +12,7 @@
#ifndef 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/BinaryFormat/ELF.h"
#include "llvm/MC/MCSymbol.h"
@ -91,79 +92,167 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Relocation &Rel) {
return OS;
}
/// A wrapper around SectionRef that also manages related relocations
class BinarySection {
SectionRef Section;
std::set<Relocation> Relocations;
public:
explicit BinarySection(SectionRef Section) : Section(Section) { }
inline uint8_t *copyByteArray(const uint8_t *Data, uint64_t Size) {
auto Array = new uint8_t[Size];
memcpy(Array, Data, Size);
return Array;
}
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;
Section.getName(Name);
return Name;
}
uint64_t getAddress() const { return Section.getAddress(); }
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 {
static StringRef getContents(SectionRef Section) {
StringRef Contents;
if (ELFSectionRef(Section).getType() != ELF::SHT_NOBITS) {
if (auto EC = Section.getContents(Contents)) {
errs() << "BOLT-ERROR: cannot get section contents for "
<< getName() << ": " << EC.message() << ".\n";
<< getName(Section) << ": " << EC.message() << ".\n";
exit(1);
}
}
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() {
return make_range(Relocations.begin(), Relocations.end());
// Set output info for this section.
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 {
return make_range(Relocations.begin(), Relocations.end());
// TODO: pass Data as StringRef/ArrayRef? use StringRef::copy method.
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 {
return !Relocations.empty();
~BinarySection();
/// 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) {
Relocation Key{Offset, 0, 0, 0, 0};
auto Itr = Relocations.find(Key);
if (Itr != Relocations.end())
Relocations.erase(Itr);
operator bool() const {
return ELFType != ELF::SHT_NULL;
}
void addRelocation(uint64_t Offset,
MCSymbol *Symbol,
uint64_t Type,
uint64_t Addend,
uint64_t Value = 0) {
assert(Offset < getSize());
Relocations.emplace(Relocation{Offset, Symbol, Type, Addend, Value});
bool operator==(const BinarySection &Other) const {
return (Name == Other.Name &&
Address == Other.Address &&
Size == Other.Size &&
getData() == Other.getData() &&
Alignment == Other.Alignment &&
ELFType == Other.ELFType &&
ELFFlags == Other.ELFFlags &&
IsLocal == Other.IsLocal);
}
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;
bool operator!=(const BinarySection &Other) const {
return !operator==(Other);
}
// Order sections by their immutable properties.
bool operator<(const BinarySection &Other) const {
return (getAddress() < Other.getAddress() ||
(getAddress() == Other.getAddress() &&
@ -171,8 +260,170 @@ public:
(getSize() == Other.getSize() &&
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 llvm

View File

@ -444,9 +444,19 @@ void RewriteInstance::updateLineTableOffsets() {
Offset += Label->getOffset() - CurrentOffset;
CurrentOffset = Label->getOffset();
auto &SI = EFMM->NoteSectionInfo[".debug_info"];
SI.PendingRelocs.emplace_back(
SectionInfo::Reloc{LTOffset, 4, 0, Offset});
auto DbgInfoSection = BC->getUniqueSectionByName(".debug_info");
assert(DbgInfoSection && ".debug_info section must exist");
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
<< " has line table at " << Offset << "\n");
@ -466,41 +476,20 @@ void RewriteInstance::finalizeDebugSections() {
RangesSectionsWriter->writeArangesSection(Writer.get());
const auto &ARangesContents = OS.str();
// Freed by ExecutableFileMemoryManager.
uint8_t *SectionData = new uint8_t[ARangesContents.size()];
memcpy(SectionData, ARangesContents.data(), ARangesContents.size());
EFMM->NoteSectionInfo[".debug_aranges"] = SectionInfo(
reinterpret_cast<uint64_t>(SectionData),
ARangesContents.size(),
/*Alignment=*/0,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false);
BC->registerOrUpdateNoteSection(".debug_aranges",
copyByteArray(ARangesContents),
ARangesContents.size());
}
auto RangesSectionContents = RangesSectionsWriter->finalize();
auto SectionSize = RangesSectionContents->size();
uint8_t *SectionData = new uint8_t[SectionSize];
memcpy(SectionData, RangesSectionContents->data(), SectionSize);
EFMM->NoteSectionInfo[".debug_ranges"] = SectionInfo(
reinterpret_cast<uint64_t>(SectionData),
SectionSize,
/*Alignment=*/1,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false);
BC->registerOrUpdateNoteSection(".debug_ranges",
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
auto LocationListSectionContents = LocationListWriter->finalize();
SectionSize = LocationListSectionContents->size();
SectionData = new uint8_t[SectionSize];
memcpy(SectionData, LocationListSectionContents->data(), SectionSize);
EFMM->NoteSectionInfo[".debug_loc"] = SectionInfo(
reinterpret_cast<uint64_t>(SectionData),
SectionSize,
/*Alignment=*/1,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false);
BC->registerOrUpdateNoteSection(".debug_loc",
copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
void RewriteInstance::updateGdbIndexSection() {
@ -569,7 +558,7 @@ void RewriteInstance::updateGdbIndexSection() {
size_t NewGdbIndexSize = GdbIndexContents.size() + Delta;
// Free'd by ExecutableFileMemoryManager.
auto * const NewGdbIndexContents = new uint8_t[NewGdbIndexSize];
auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize];
auto *Buffer = NewGdbIndexContents;
write32le(Buffer, Version);
@ -606,11 +595,7 @@ void RewriteInstance::updateGdbIndexSection() {
memcpy(Buffer, Data, TrailingSize);
// Register the new section.
EFMM->NoteSectionInfo[".gdb_index"] = SectionInfo(
reinterpret_cast<uint64_t>(NewGdbIndexContents),
NewGdbIndexSize,
/*Alignment=*/0,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false);
BC->registerOrUpdateNoteSection(".gdb_index",
NewGdbIndexContents,
NewGdbIndexSize);
}

View File

@ -220,6 +220,13 @@ PrintDisasm("print-disasm",
cl::Hidden,
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>
PrintLoopInfo("print-loops",
cl::desc("print loop related information"),
@ -459,55 +466,44 @@ uint8_t *ExecutableFileMemoryManager::allocateSection(intptr_t Size,
for (auto &OverwriteName : RewriteInstance::SectionsToOverwrite) {
if (SectionName == OverwriteName) {
uint8_t *DataCopy = new uint8_t[Size];
DEBUG(dbgs() << "BOLT: note section " << SectionName << " with size "
<< Size << ", alignment " << Alignment << " at 0x"
<< Twine::utohexstr(reinterpret_cast<uint64_t>(DataCopy))
<< '\n');
NoteSectionInfo[SectionName] =
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
auto &Section = BC.registerOrUpdateNoteSection(SectionName,
DataCopy,
Size,
Alignment,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false,
0,
0,
SectionID);
Alignment);
Section.setSectionID(SectionID);
assert(!Section.isAllocatable() && "note sections cannot be allocatable");
return DataCopy;
}
}
uint8_t *ret;
uint8_t *Ret;
if (IsCode) {
ret = SectionMemoryManager::allocateCodeSection(Size, Alignment,
Ret = SectionMemoryManager::allocateCodeSection(Size, Alignment,
SectionID, SectionName);
} else {
ret = SectionMemoryManager::allocateDataSection(Size, Alignment,
Ret = SectionMemoryManager::allocateDataSection(Size, Alignment,
SectionID, SectionName,
IsReadOnly);
}
bool IsLocal = false;
if (SectionName.startswith(".local."))
IsLocal = true;
const auto Flags = BinarySection::getFlags(IsReadOnly, IsCode, true);
auto &Section = BC.registerOrUpdateSection(SectionName,
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"))
<< " section : " << SectionName
<< " with size " << Size << ", alignment " << Alignment
<< " at 0x" << ret << "\n");
<< " at 0x" << Ret << ", ID = " << SectionID << "\n");
SectionMapInfo[SectionName] = SectionInfo(reinterpret_cast<uint64_t>(ret),
Size,
Alignment,
IsCode,
IsReadOnly,
IsLocal,
0,
0,
SectionID);
return ret;
return Ret;
}
/// Notifier for non-allocatable (note) section.
@ -522,21 +518,13 @@ uint8_t *ExecutableFileMemoryManager::recordNoteSection(
<< " with size " << Size << ", alignment " << Alignment
<< " at 0x"
<< Twine::utohexstr(reinterpret_cast<uint64_t>(Data)) << '\n');
// We need to make a copy of the section contents if we'll need it for
// a future reference. RuntimeDyld will not allocate the space forus.
uint8_t *DataCopy = new uint8_t[Size];
memcpy(DataCopy, Data, Size);
NoteSectionInfo[SectionName] =
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
auto &Section = BC.registerOrUpdateNoteSection(SectionName,
copyByteArray(Data, Size),
Size,
Alignment,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false,
0,
0,
SectionID);
return DataCopy;
Alignment);
Section.setSectionID(SectionID);
assert(!Section.isAllocatable() && "note sections cannot be allocatable");
return Section.getOutputData();
}
bool ExecutableFileMemoryManager::finalizeMemory(std::string *ErrMsg) {
@ -544,11 +532,7 @@ bool ExecutableFileMemoryManager::finalizeMemory(std::string *ErrMsg) {
return SectionMemoryManager::finalizeMemory(ErrMsg);
}
ExecutableFileMemoryManager::~ExecutableFileMemoryManager() {
for (auto &SII : NoteSectionInfo) {
delete[] reinterpret_cast<uint8_t *>(SII.second.AllocAddress);
}
}
ExecutableFileMemoryManager::~ExecutableFileMemoryManager() { }
namespace {
@ -717,8 +701,7 @@ void RewriteInstance::discoverStorage() {
// 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
// of the original one seen in the binary.
EFMM.reset(new ExecutableFileMemoryManager(
/*AllowStubs*/ false));
EFMM.reset(new ExecutableFileMemoryManager(*BC, /*AllowStubs*/ false));
auto ELF64LEFile = dyn_cast<ELF64LEObjectFile>(InputFile);
if (!ELF64LEFile) {
@ -1285,9 +1268,10 @@ void RewriteInstance::discoverFileObjects() {
}
BF->addAlternativeName(UniqueName);
} else {
auto BS = BC->getSectionForAddress(Address);
assert(BS && "section for functions must be registered.");
BF = createBinaryFunction(UniqueName, *BS, Address, SymbolSize, IsSimple);
auto Section = BC->getSectionForAddress(Address);
assert(Section && "section for functions must be registered.");
BF = createBinaryFunction(UniqueName, *Section, Address,
SymbolSize, IsSimple);
}
if (!AlternativeName.empty())
BF->addAlternativeName(AlternativeName);
@ -1521,8 +1505,8 @@ void RewriteInstance::relocateEHFrameSection() {
assert(EHFrameSection && "non-empty .eh_frame section expected");
DWARFDebugFrame EHFrame(true, EHFrameSection->getAddress());
StringRef EHFrameSectionContents = EHFrameSection->getContents();
DWARFDataExtractor DE(EHFrameSectionContents, BC->AsmInfo->isLittleEndian(),
DWARFDataExtractor DE(EHFrameSection->getContents(),
BC->AsmInfo->isLittleEndian(),
BC->AsmInfo->getCodePointerSize());
auto createReloc = [&](uint64_t Value, uint64_t Offset, uint64_t DwarfType) {
if (DwarfType == dwarf::DW_EH_PE_omit)
@ -1564,7 +1548,7 @@ void RewriteInstance::relocateEHFrameSection() {
DEBUG(dbgs() << "BOLT-DEBUG: adding DWARF reference against symbol "
<< Symbol->getName() << '\n');
BC->addSectionRelocation(*EHFrameSection, Offset, Symbol, RelType);
EHFrameSection->addRelocation(Offset, Symbol, RelType, 0);
};
EHFrame.parse(DE, createReloc);
@ -1594,7 +1578,7 @@ void RewriteInstance::readSpecialSections() {
check_error(Section.getName(SectionName), "cannot get section name");
StringRef SectionContents;
ArrayRef<uint8_t> SectionData;
if (!(ELFSectionRef(Section).getType() & ELF::SHT_NOBITS)) {
if (ELFSectionRef(Section).getType() != ELF::SHT_NOBITS) {
check_error(Section.getContents(SectionContents),
"cannot get section contents");
SectionData = ArrayRef<uint8_t>(
@ -1611,12 +1595,20 @@ void RewriteInstance::readSpecialSections() {
HasTextRelocations = true;
}
// Only register sections with names.
if (!getSectionName(Section).empty()) {
BC->registerSection(Section);
DEBUG(dbgs() << "BOLT-DEBUG: registering section " << SectionName
<< " @ 0x" << Twine::utohexstr(Section.getAddress()) << ":0x"
<< Twine::utohexstr(Section.getAddress() + Section.getSize())
<< "\n");
}
}
if (opts::PrintSections) {
outs() << "BOLT-INFO: Sections from original binary:\n";
BC->printSections(outs());
}
EHFrameSection = BC->getUniqueSectionByName(".eh_frame");
GdbIndexSection = BC->getUniqueSectionByName(".gdb_index");
@ -2549,19 +2541,18 @@ void RewriteInstance::mapFileSections(
orc::RTDyldObjectLinkingLayer::ObjHandleT &ObjectsHandle) {
NewTextSectionStartAddress = NextAvailableAddress;
if (BC->HasRelocations) {
auto SMII = EFMM->SectionMapInfo.find(".text");
assert(SMII != EFMM->SectionMapInfo.end() &&
".text not found in output");
auto &SI = SMII->second;
auto TextSection = BC->getUniqueSectionByName(".text");
assert(TextSection && ".text not found in output");
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";
// Utilize the original .text for storage.
NewTextSectionStartAddress = BC->OldTextSectionAddress;
NewTextSectionOffset = BC->OldTextSectionOffset;
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
if (Padding + SI.Size <= BC->OldTextSectionSize) {
if (Padding + TextSection->getOutputSize() <= BC->OldTextSectionSize) {
outs() << "BOLT-INFO: using 0x200000 alignment\n";
NewTextSectionStartAddress += Padding;
NewTextSectionOffset += Padding;
@ -2569,24 +2560,24 @@ void RewriteInstance::mapFileSections(
} else {
if (opts::UseOldText) {
errs() << "BOLT-ERROR: original .text too small to fit the new code. "
<< SI.Size << " bytes needed, have " << BC->OldTextSectionSize
<< " bytes available.\n";
<< TextSection->getOutputSize() << " bytes needed, have "
<< BC->OldTextSectionSize << " bytes available.\n";
}
auto Padding = OffsetToAlignment(NewTextSectionStartAddress, PageAlign);
NextAvailableAddress += Padding;
NewTextSectionStartAddress = NextAvailableAddress;
NewTextSectionOffset = getFileOffsetForAddress(NextAvailableAddress);
NextAvailableAddress += Padding + SI.Size;
NextAvailableAddress += Padding + TextSection->getOutputSize();
}
SI.FileAddress = NewTextSectionStartAddress;
SI.FileOffset = NewTextSectionOffset;
TextSection->setFileAddress(NewTextSectionStartAddress);
TextSection->setFileOffset(NewTextSectionOffset);
DEBUG(dbgs() << "BOLT: mapping .text 0x"
<< Twine::utohexstr(SMII->second.AllocAddress)
<< Twine::utohexstr(TextSection->getAllocAddress())
<< " to 0x" << Twine::utohexstr(NewTextSectionStartAddress)
<< '\n');
OLT->mapSectionAddress(ObjectsHandle,
SI.SectionID,
TextSection->getSectionID(),
NewTextSectionStartAddress);
} else {
for (auto &BFI : BinaryFunctions) {
@ -2595,18 +2586,17 @@ void RewriteInstance::mapFileSections(
continue;
auto TooLarge = false;
auto SMII = EFMM->SectionMapInfo.find(Function.getCodeSectionName());
assert(SMII != EFMM->SectionMapInfo.end() &&
"cannot find section for function");
auto FuncSection = BC->getUniqueSectionByName(Function.getCodeSectionName());
assert(FuncSection && "cannot find section for function");
DEBUG(dbgs() << "BOLT: mapping 0x"
<< Twine::utohexstr(SMII->second.AllocAddress)
<< Twine::utohexstr(FuncSection->getAllocAddress())
<< " to 0x" << Twine::utohexstr(Function.getAddress())
<< '\n');
OLT->mapSectionAddress(ObjectsHandle,
SMII->second.SectionID,
FuncSection->getSectionID(),
Function.getAddress());
Function.setImageAddress(SMII->second.AllocAddress);
Function.setImageSize(SMII->second.Size);
Function.setImageAddress(FuncSection->getAllocAddress());
Function.setImageSize(FuncSection->getOutputSize());
if (Function.getImageSize() > Function.getMaxSize()) {
TooLarge = true;
FailedAddresses.emplace_back(Function.getAddress());
@ -2616,15 +2606,13 @@ void RewriteInstance::mapFileSections(
if (opts::JumpTables == JTS_BASIC) {
for (auto &JTI : Function.JumpTables) {
auto &JT = JTI.second;
auto SMII = EFMM->SectionMapInfo.find(JT.SectionName);
assert(SMII != EFMM->SectionMapInfo.end() &&
"cannot find section for jump table");
JT.SecInfo = &SMII->second;
JT.SecInfo->FileAddress = JT.Address;
JT.Section = BC->getUniqueSectionByName(JT.SectionName);
assert(JT.Section && "cannot find section for jump table");
JT.Section->setFileAddress(JT.Address);
DEBUG(dbgs() << "BOLT-DEBUG: mapping " << JT.SectionName << " to 0x"
<< Twine::utohexstr(JT.Address) << '\n');
OLT->mapSectionAddress(ObjectsHandle,
JT.SecInfo->SectionID,
JT.Section->getSectionID(),
JT.Address);
}
}
@ -2632,9 +2620,9 @@ void RewriteInstance::mapFileSections(
if (!Function.isSplit())
continue;
SMII = EFMM->SectionMapInfo.find(Function.getColdCodeSectionName());
assert(SMII != EFMM->SectionMapInfo.end() &&
"cannot find section for cold part");
auto ColdSection =
BC->getUniqueSectionByName(Function.getColdCodeSectionName());
assert(ColdSection && "cannot find section for cold part");
// Cold fragments are aligned at 16 bytes.
NextAvailableAddress = alignTo(NextAvailableAddress, 16);
auto &ColdPart = Function.cold();
@ -2646,8 +2634,8 @@ void RewriteInstance::mapFileSections(
ColdPart.setFileOffset(0);
} else {
ColdPart.setAddress(NextAvailableAddress);
ColdPart.setImageAddress(SMII->second.AllocAddress);
ColdPart.setImageSize(SMII->second.Size);
ColdPart.setImageAddress(ColdSection->getAllocAddress());
ColdPart.setImageSize(ColdSection->getOutputSize());
ColdPart.setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
}
@ -2658,7 +2646,7 @@ void RewriteInstance::mapFileSections(
<< " with size "
<< Twine::utohexstr(ColdPart.getImageSize()) << '\n');
OLT->mapSectionAddress(ObjectsHandle,
SMII->second.SectionID,
ColdSection->getSectionID(),
ColdPart.getAddress());
NextAvailableAddress += ColdPart.getImageSize();
@ -2669,14 +2657,18 @@ void RewriteInstance::mapFileSections(
// entry in section header table.
auto NewTextSectionSize = NextAvailableAddress - NewTextSectionStartAddress;
if (NewTextSectionSize) {
EFMM->SectionMapInfo[BOLTSecPrefix + ".text"] =
SectionInfo(0,
const auto Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
/*IsText=*/true,
/*IsAllocatable=*/true);
auto &Section = BC->registerOrUpdateSection(BOLTSecPrefix + ".text",
ELF::SHT_PROGBITS,
Flags,
nullptr,
NewTextSectionSize,
16,
true /*IsCode*/,
true /*IsReadOnly*/,
true /*IsLocal*/,
NewTextSectionStartAddress,
true /*IsLocal*/);
Section.setFileAddress(NewTextSectionStartAddress);
Section.setFileOffset(
getFileOffsetForAddress(NewTextSectionStartAddress));
}
}
@ -2688,55 +2680,58 @@ void RewriteInstance::mapFileSections(
".gcc_except_table",
".rodata", ".rodata.cold" };
for (auto &SectionName : Sections) {
auto SMII = EFMM->SectionMapInfo.find(SectionName);
if (SMII == EFMM->SectionMapInfo.end())
auto Section = BC->getUniqueSectionByName(SectionName);
if (!Section || !Section->isAllocatable() || !Section->isFinalized())
continue;
SectionInfo &SI = SMII->second;
NextAvailableAddress = alignTo(NextAvailableAddress, SI.Alignment);
NextAvailableAddress = alignTo(NextAvailableAddress,
Section->getAlignment());
DEBUG(dbgs() << "BOLT: mapping section " << SectionName << " (0x"
<< Twine::utohexstr(SI.AllocAddress)
<< Twine::utohexstr(Section->getAllocAddress())
<< ") to 0x" << Twine::utohexstr(NextAvailableAddress)
<< '\n');
OLT->mapSectionAddress(ObjectsHandle,
SI.SectionID,
Section->getSectionID(),
NextAvailableAddress);
SI.FileAddress = NextAvailableAddress;
SI.FileOffset = getFileOffsetForAddress(NextAvailableAddress);
Section->setFileAddress(NextAvailableAddress);
Section->setFileOffset(getFileOffsetForAddress(NextAvailableAddress));
NextAvailableAddress += SI.Size;
NextAvailableAddress += Section->getOutputSize();
}
// Handling for sections with relocations.
for (const auto &Section : BC->sections()) {
if (!Section.hasRelocations())
if (!Section ||
!Section.hasRelocations() ||
!Section.hasSectionRef())
continue;
StringRef SectionName = Section.getName();
auto SMII = EFMM->SectionMapInfo.find(OrgSecPrefix +
std::string(SectionName));
if (SMII == EFMM->SectionMapInfo.end())
auto OrgSection =
BC->getUniqueSectionByName(OrgSecPrefix + std::string(SectionName));
if (!OrgSection ||
!OrgSection->isAllocatable() ||
!OrgSection->isFinalized())
continue;
SectionInfo &SI = SMII->second;
if (SI.FileAddress) {
if (OrgSection->getFileAddress()) {
DEBUG(dbgs() << "BOLT-DEBUG: section " << SectionName
<< " is already mapped at 0x"
<< Twine::utohexstr(SI.FileAddress) << '\n');
<< Twine::utohexstr(OrgSection->getFileAddress()) << '\n');
continue;
}
DEBUG(dbgs() << "BOLT: mapping original section " << SectionName << " (0x"
<< Twine::utohexstr(SI.AllocAddress)
<< Twine::utohexstr(OrgSection->getAllocAddress())
<< ") to 0x" << Twine::utohexstr(Section.getAddress())
<< '\n');
OLT->mapSectionAddress(ObjectsHandle,
SI.SectionID,
OrgSection->getSectionID(),
Section.getAddress());
SI.FileAddress = Section.getAddress();
StringRef SectionContents = Section.getContents();
SI.FileOffset = SectionContents.data() - InputFile->getData().data();
OrgSection->setFileAddress(Section.getAddress());
OrgSection->setFileOffset(Section.getContents().data() -
InputFile->getData().data());
}
}
@ -2826,20 +2821,18 @@ void RewriteInstance::updateOutputValues(const MCAsmLayout &Layout) {
void RewriteInstance::emitDataSection(MCStreamer *Streamer,
const BinarySection &Section,
std::string Name) {
StringRef SectionName = !Name.empty() ? StringRef(Name) : Section.getName();
const auto SectionFlags = Section.getFlags();
const auto SectionType = Section.getType();
StringRef Name) {
StringRef SectionName = !Name.empty() ? Name : Section.getName();
StringRef SectionContents = Section.getContents();
auto *ELFSection = BC->Ctx->getELFSection(SectionName,
SectionType,
SectionFlags);
Section.getELFType(),
Section.getELFFlags());
Streamer->SwitchSection(ELFSection);
Streamer->EmitValueToAlignment(Section.getAlignment());
DEBUG(dbgs() << "BOLT-DEBUG: emitting "
<< (SectionFlags & ELF::SHF_ALLOC ? "" : "non-")
<< (Section.isAllocatable() ? "" : "non-")
<< "allocatable data section " << SectionName << '\n');
if (!Section.hasRelocations()) {
@ -2872,7 +2865,7 @@ void RewriteInstance::emitDataSection(MCStreamer *Streamer,
void RewriteInstance::emitDataSections(MCStreamer *Streamer) {
for (const auto &Section : BC->sections()) {
if (!Section.hasRelocations())
if (!Section || !Section.hasRelocations() || !Section.hasSectionRef())
continue;
StringRef SectionName = Section.getName();
@ -2943,14 +2936,15 @@ void RewriteInstance::patchELFPHDRTable() {
NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum;
NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
} else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
auto SMII = EFMM->SectionMapInfo.find(".eh_frame_hdr");
if (SMII != EFMM->SectionMapInfo.end()) {
auto &EHFrameHdrSecInfo = SMII->second;
NewPhdr.p_offset = EHFrameHdrSecInfo.FileOffset;
NewPhdr.p_vaddr = EHFrameHdrSecInfo.FileAddress;
NewPhdr.p_paddr = EHFrameHdrSecInfo.FileAddress;
NewPhdr.p_filesz = EHFrameHdrSecInfo.Size;
NewPhdr.p_memsz = EHFrameHdrSecInfo.Size;
auto EHFrameHdrSec = BC->getUniqueSectionByName(".eh_frame_hdr");
if (EHFrameHdrSec &&
EHFrameHdrSec->isAllocatable() &&
EHFrameHdrSec->isFinalized()) {
NewPhdr.p_offset = EHFrameHdrSec->getFileOffset();
NewPhdr.p_vaddr = EHFrameHdrSec->getFileAddress();
NewPhdr.p_paddr = EHFrameHdrSec->getFileAddress();
NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize();
NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize();
}
} else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) {
NewPhdr.p_type = ELF::PT_LOAD;
@ -3053,75 +3047,79 @@ void RewriteInstance::rewriteNoteSections() {
Size = appendPadding(OS, Size, Section.sh_addralign);
}
// Address of extension to the section.
uint64_t Address{0};
// Perform section post-processing.
auto SII = EFMM->NoteSectionInfo.find(SectionName);
if (SII != EFMM->NoteSectionInfo.end()) {
auto &SI = SII->second;
assert(SI.Alignment <= Section.sh_addralign &&
auto BSec = BC->getUniqueSectionByName(SectionName);
uint8_t *SectionData = nullptr;
if (BSec && !BSec->isAllocatable()) {
assert(BSec->getAlignment() <= Section.sh_addralign &&
"alignment exceeds value in file");
// Write section extension.
Address = SI.AllocAddress;
if (Address) {
if (BSec->getAllocAddress()) {
SectionData = BSec->getOutputData();
DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
<< " contents to section "
<< SectionName << '\n');
OS.write(reinterpret_cast<const char *>(Address), SI.Size);
Size += SI.Size;
OS.write(reinterpret_cast<char *>(SectionData),
BSec->getOutputSize());
Size += BSec->getOutputSize();
}
if (!SI.PendingRelocs.empty()) {
if (BSec->hasPendingRelocations()) {
DEBUG(dbgs() << "BOLT-DEBUG: processing relocs for section "
<< SectionName << '\n');
for (auto &Reloc : SI.PendingRelocs) {
DEBUG(dbgs() << "BOLT-DEBUG: writing value "
<< Twine::utohexstr(Reloc.Value)
<< " of size " << (unsigned)Reloc.Size
<< " at offset "
for (auto &Reloc : BSec->pendingRelocations()) {
DEBUG(dbgs() << "BOLT-DEBUG: writing value 0x"
<< Twine::utohexstr(Reloc.Addend)
<< " of size " << Relocation::getSizeForType(Reloc.Type)
<< " at offset 0x"
<< Twine::utohexstr(Reloc.Offset) << '\n');
assert(Reloc.Size == 4 &&
"only relocations of size 4 are supported at the moment");
OS.pwrite(reinterpret_cast<const char*>(&Reloc.Value),
Reloc.Size,
assert(Reloc.Type == ELF::R_X86_64_32 &&
"only R_X86_64_32 relocations are supported at the moment");
uint32_t Value = Reloc.Addend;
OS.pwrite(reinterpret_cast<const char*>(&Value),
Relocation::getSizeForType(Reloc.Type),
NextAvailableOffset + Reloc.Offset);
}
}
}
// Set/modify section info.
EFMM->NoteSectionInfo[SectionName] =
SectionInfo(Address,
auto &NewSection =
BC->registerOrUpdateNoteSection(SectionName,
SectionData,
Size,
Section.sh_addralign,
/*IsCode=*/false,
/*IsReadOnly=*/false,
/*IsLocal=*/false,
/*FileAddress=*/0,
NextAvailableOffset);
BSec ? BSec->isReadOnly() : false,
BSec ? BSec->getELFType()
: ELF::SHT_PROGBITS,
BSec ? BSec->isLocal() : false);
NewSection.setFileAddress(0);
NewSection.setFileOffset(NextAvailableOffset);
NextAvailableOffset += Size;
}
// Write new note sections.
for (auto &SII : EFMM->NoteSectionInfo) {
auto &SI = SII.second;
if (SI.FileOffset || !SI.AllocAddress)
for (auto &Section : BC->sections()) {
if (!Section ||
Section.getFileOffset() ||
!Section.getAllocAddress() ||
Section.isAllocatable())
continue;
assert(SI.PendingRelocs.empty() && "cannot have pending relocs");
assert(!Section.hasPendingRelocations() && "cannot have pending relocs");
NextAvailableOffset = appendPadding(OS, NextAvailableOffset, SI.Alignment);
SI.FileOffset = NextAvailableOffset;
NextAvailableOffset = appendPadding(OS, NextAvailableOffset,
Section.getAlignment());
Section.setFileOffset(NextAvailableOffset);
DEBUG(dbgs() << "BOLT-DEBUG: writing out new section " << SII.first
<< " of size " << SI.Size << " at offset 0x"
<< Twine::utohexstr(SI.FileOffset) << '\n');
DEBUG(dbgs() << "BOLT-DEBUG: writing out new section "
<< Section.getName() << " of size " << Section.getOutputSize()
<< " at offset 0x" << Twine::utohexstr(Section.getFileOffset())
<< '\n');
OS.write(reinterpret_cast<const char *>(SI.AllocAddress), SI.Size);
NextAvailableOffset += SI.Size;
OS.write(Section.getOutputContents().data(), Section.getOutputSize());
NextAvailableOffset += Section.getOutputSize();
}
}
@ -3140,11 +3138,10 @@ void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
SHStrTab.add(*AllSHStrTabStrings.back());
}
}
for (auto &SMII : EFMM->SectionMapInfo) {
SHStrTab.add(SMII.first);
for (auto &Section : BC->sections()) {
if (Section) {
SHStrTab.add(Section.getName());
}
for (auto &SMII : EFMM->NoteSectionInfo) {
SHStrTab.add(SMII.first);
}
SHStrTab.finalize();
@ -3152,14 +3149,12 @@ void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *File) {
uint8_t *DataCopy = new uint8_t[SHStrTabSize];
memset(DataCopy, 0, SHStrTabSize);
SHStrTab.write(DataCopy);
EFMM->NoteSectionInfo[".shstrtab"] =
SectionInfo(reinterpret_cast<uint64_t>(DataCopy),
BC->registerOrUpdateNoteSection(".shstrtab",
DataCopy,
SHStrTabSize,
/*Alignment*/1,
/*IsCode=*/false,
/*IsReadOnly=*/false,
/*IsLocal=*/false);
EFMM->NoteSectionInfo[".shstrtab"].IsStrTab = true;
/*Alignment=*/1,
/*IsReadOnly=*/true,
ELF::SHT_STRTAB);
}
void RewriteInstance::addBoltInfoSection() {
@ -3194,16 +3189,12 @@ void RewriteInstance::addBoltInfoSection() {
}
const auto BoltInfo = OS.str();
const auto SectionSize = BoltInfo.size();
uint8_t *SectionData = new uint8_t[SectionSize];
memcpy(SectionData, BoltInfo.data(), SectionSize);
EFMM->NoteSectionInfo[".note.bolt_info"] =
SectionInfo(reinterpret_cast<uint64_t>(SectionData), SectionSize,
BC->registerOrUpdateNoteSection(".note.bolt_info",
copyByteArray(BoltInfo),
BoltInfo.size(),
/*Alignment=*/1,
/*IsCode=*/false,
/*IsReadOnly=*/true,
/*IsLocal=*/false, 0, 0, 0,
/*IsELFNote=*/true);
ELF::SHT_NOTE);
}
}
@ -3275,20 +3266,21 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
}
// 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) {
NewTextSectionIndex = CurIndex;
}
// Process entries for all new allocatable sections.
for (auto &SMII : EFMM->SectionMapInfo) {
const auto &SectionName = SMII.first;
const auto &SI = SMII.second;
for (auto &Section : BC->sections()) {
if (!Section || !Section.isAllocatable() || !Section.isFinalized())
continue;
// Ignore function sections.
if (SI.FileAddress < NewTextSegmentAddress) {
if (Section.getFileAddress() < NewTextSegmentAddress) {
if (opts::Verbosity)
outs() << "BOLT-INFO: not writing section header for existing section "
<< SMII.first << '\n';
<< Section.getName() << '\n';
continue;
}
@ -3298,18 +3290,19 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
continue;
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;
NewSection.sh_name = SHStrTab.getOffset(SectionName);
NewSection.sh_name = SHStrTab.getOffset(Section.getName());
NewSection.sh_type = ELF::SHT_PROGBITS;
NewSection.sh_addr = SI.FileAddress;
NewSection.sh_offset = SI.FileOffset;
NewSection.sh_size = SI.Size;
NewSection.sh_addr = Section.getFileAddress();
NewSection.sh_offset = Section.getFileOffset();
NewSection.sh_size = Section.getOutputSize();
NewSection.sh_entsize = 0;
NewSection.sh_flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
NewSection.sh_flags = Section.getELFFlags();
NewSection.sh_link = 0;
NewSection.sh_info = 0;
NewSection.sh_addralign = SI.Alignment;
NewSection.sh_addralign = Section.getAlignment();
OutputSections->emplace_back(NewSection);
}
@ -3336,19 +3329,17 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
StringRef SectionName =
cantFail(Obj->getSectionName(&Section), "cannot get section name");
auto SII = EFMM->NoteSectionInfo.find(SectionName);
assert(SII != EFMM->NoteSectionInfo.end() &&
"missing section info for non-allocatable section");
auto BSec = BC->getUniqueSectionByName(SectionName);
assert(BSec && "missing section info for non-allocatable section");
const auto &SI = SII->second;
auto NewSection = Section;
NewSection.sh_offset = SI.FileOffset;
NewSection.sh_size = SI.Size;
NewSection.sh_offset = BSec->getFileOffset();
NewSection.sh_size = BSec->getOutputSize();
NewSection.sh_name = SHStrTab.getOffset(SectionName);
OutputSections->emplace_back(NewSection);
LastFileOffset = SI.FileOffset;
LastFileOffset = BSec->getFileOffset();
}
// Map input -> output is ready. Early return if that's all we need.
@ -3356,28 +3347,27 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
return NewSectionIndex;
// Create entries for new non-allocatable sections.
for (auto &SII : EFMM->NoteSectionInfo) {
const auto &SectionName = SII.first;
const auto &SI = SII.second;
if (SI.FileOffset <= LastFileOffset)
for (auto &Section : BC->sections()) {
if (!Section ||
Section.isAllocatable() ||
Section.getFileOffset() <= LastFileOffset)
continue;
if (opts::Verbosity >= 1)
outs() << "BOLT-INFO: writing section header for " << SectionName << '\n';
if (opts::Verbosity >= 1) {
outs() << "BOLT-INFO: writing section header for "
<< Section.getName() << '\n';
}
ELFShdrTy NewSection;
NewSection.sh_name = SHStrTab.getOffset(SectionName);
NewSection.sh_type =
(SI.IsStrTab ? ELF::SHT_STRTAB
: SI.IsELFNote ? ELF::SHT_NOTE : ELF::SHT_PROGBITS);
NewSection.sh_name = SHStrTab.getOffset(Section.getName());
NewSection.sh_type = Section.getELFType();
NewSection.sh_addr = 0;
NewSection.sh_offset = SI.FileOffset;
NewSection.sh_size = SI.Size;
NewSection.sh_offset = Section.getFileOffset();
NewSection.sh_size = Section.getOutputSize();
NewSection.sh_entsize = 0;
NewSection.sh_flags = 0;
NewSection.sh_flags = Section.getELFFlags();
NewSection.sh_link = 0;
NewSection.sh_info = 0;
NewSection.sh_addralign = SI.Alignment ? SI.Alignment : 1;
NewSection.sh_addralign = Section.getAlignment();
OutputSections->emplace_back(NewSection);
}
@ -3660,23 +3650,19 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
return Idx;
});
uint8_t *DataCopy = new uint8_t[NewContents.size()];
memcpy(DataCopy, NewContents.data(), NewContents.size());
EFMM->NoteSectionInfo[SecName] =
SectionInfo(reinterpret_cast<uint64_t>(DataCopy), NewContents.size(),
/*Alignment*/ 1,
/*IsCode=*/false,
/*IsReadOnly=*/false,
/*IsLocal=*/false);
DataCopy = new uint8_t[NewStrTab.size()];
memcpy(DataCopy, NewStrTab.data(), NewStrTab.size());
EFMM->NoteSectionInfo[StrSecName] =
SectionInfo(reinterpret_cast<uint64_t>(DataCopy), NewStrTab.size(),
/*Alignment*/ 1,
/*IsCode=*/false,
/*IsReadOnly=*/false,
/*IsLocal=*/false);
EFMM->NoteSectionInfo[StrSecName].IsStrTab = true;
BC->registerOrUpdateNoteSection(SecName,
copyByteArray(NewContents),
NewContents.size(),
/*Alignment=*/1,
/*IsReadOnly=*/true,
ELF::SHT_SYMTAB);
BC->registerOrUpdateNoteSection(StrSecName,
copyByteArray(NewStrTab),
NewStrTab.size(),
/*Alignment=*/1,
/*IsReadOnly=*/true,
ELF::SHT_STRTAB);
}
template <typename ELFT>
@ -3892,13 +3878,12 @@ void RewriteInstance::rewriteFile() {
if (opts::JumpTables == JTS_BASIC) {
for (auto &JTI : Function.JumpTables) {
auto &JT = JTI.second;
assert(JT.SecInfo && "section info for jump table expected");
JT.SecInfo->FileOffset =
getFileOffsetForAddress(JT.Address);
assert(JT.SecInfo->FileOffset && "no matching offset in file");
Out->os().pwrite(reinterpret_cast<char *>(JT.SecInfo->AllocAddress),
JT.SecInfo->Size,
JT.SecInfo->FileOffset);
assert(JT.Section && "section for jump table expected");
JT.Section->setFileOffset(getFileOffsetForAddress(JT.Address));
assert(JT.Section->getFileOffset() && "no matching offset in file");
OS.pwrite(reinterpret_cast<const char*>(JT.Section->getOutputData()),
JT.Section->getOutputSize(),
JT.Section->getFileOffset());
}
}
@ -3959,27 +3944,26 @@ void RewriteInstance::rewriteFile() {
}
// Write all non-local sections, i.e. those not emitted with the function.
for (auto &SMII : EFMM->SectionMapInfo) {
SectionInfo &SI = SMII.second;
if (SI.IsLocal)
for (auto &Section : BC->sections()) {
if (!Section ||
!Section.isAllocatable() ||
!Section.isFinalized() ||
Section.isLocal())
continue;
if (opts::Verbosity >= 1) {
outs() << "BOLT: writing new section " << SMII.first << '\n';
outs() << " data at 0x" << Twine::utohexstr(SI.AllocAddress) << '\n';
outs() << " of size " << SI.Size << '\n';
outs() << " at offset " << SI.FileOffset << '\n';
outs() << "BOLT: writing new section " << Section.getName() << '\n';
outs() << " data at 0x" << Twine::utohexstr(Section.getAllocAddress()) << '\n';
outs() << " of size " << Section.getOutputSize() << '\n';
outs() << " at offset " << Section.getFileOffset() << '\n';
}
OS.pwrite(reinterpret_cast<const char *>(SI.AllocAddress),
SI.Size,
SI.FileOffset);
assert(SI.AllocAddress &&
"writing section that was not assigned an address");
OS.pwrite(reinterpret_cast<const char*>(Section.getOutputData()),
Section.getOutputSize(),
Section.getFileOffset());
}
// If .eh_frame is present create .eh_frame_hdr.
auto SMII = EFMM->SectionMapInfo.find(".eh_frame");
if (SMII != EFMM->SectionMapInfo.end()) {
writeEHFrameHeader(SMII->second);
if (EHFrameSection && EHFrameSection->isFinalized()) {
writeEHFrameHeader();
}
// Patch program header table.
@ -4006,6 +3990,11 @@ void RewriteInstance::rewriteFile() {
// Update ELF book-keeping info.
patchELFSectionHeaderTable();
if (opts::PrintSections) {
outs() << "BOLT-INFO: Sections after processing:\n";
BC->printSections(outs());
}
Out->keep();
// 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) {
DWARFDebugFrame NewEHFrame(true, EHFrameSecInfo.FileAddress);
NewEHFrame.parse(DWARFDataExtractor(
StringRef(reinterpret_cast<const char *>(EHFrameSecInfo.AllocAddress),
EHFrameSecInfo.Size),
BC->AsmInfo->isLittleEndian(), BC->AsmInfo->getCodePointerSize()));
void RewriteInstance::writeEHFrameHeader() {
DWARFDebugFrame NewEHFrame(true, EHFrameSection->getFileAddress());
NewEHFrame.parse(DWARFDataExtractor(EHFrameSection->getOutputContents(),
BC->AsmInfo->isLittleEndian(),
BC->AsmInfo->getCodePointerSize()));
auto OldSMII = EFMM->SectionMapInfo.find(".eh_frame_old");
assert(OldSMII != EFMM->SectionMapInfo.end() &&
"expected .eh_frame_old to be present");
auto &OldEHFrameSecInfo = OldSMII->second;
DWARFDebugFrame OldEHFrame(true, OldEHFrameSecInfo.FileAddress);
OldEHFrame.parse(DWARFDataExtractor(
StringRef(reinterpret_cast<const char *>(OldEHFrameSecInfo.AllocAddress),
OldEHFrameSecInfo.Size),
BC->AsmInfo->isLittleEndian(), BC->AsmInfo->getCodePointerSize()));
auto OldEHFrameSection = BC->getUniqueSectionByName(".eh_frame_old");
assert(OldEHFrameSection && "expected .eh_frame_old to be present");
DWARFDebugFrame OldEHFrame(true, OldEHFrameSection->getFileAddress());
OldEHFrame.parse(DWARFDataExtractor(OldEHFrameSection->getOutputContents(),
BC->AsmInfo->isLittleEndian(),
BC->AsmInfo->getCodePointerSize()));
DEBUG(dbgs() << "BOLT: writing a new .eh_frame_hdr\n");
NextAvailableAddress =
appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
SectionInfo EHFrameHdrSecInfo;
EHFrameHdrSecInfo.FileAddress = NextAvailableAddress;
EHFrameHdrSecInfo.FileOffset = getFileOffsetForAddress(NextAvailableAddress);
const auto EHFrameHdrFileAddress = NextAvailableAddress;
const auto EHFrameHdrFileOffset =
getFileOffsetForAddress(NextAvailableAddress);
auto NewEHFrameHdr =
CFIRdWrt->generateEHFrameHeader(OldEHFrame,
NewEHFrame,
EHFrameHdrSecInfo.FileAddress,
EHFrameHdrFileAddress,
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 &&
"offset mismatch");
Out->os().write(NewEHFrameHdr.data(), EHFrameHdrSecInfo.Size);
const auto Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
/*IsText=*/false,
/*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 += EHFrameHdrSecInfo.Size;
NextAvailableAddress += EHFrameHdrSec.getOutputSize();
// Merge .eh_frame and .eh_frame_old so that gdb can locate all FDEs.
EHFrameSecInfo.Size = OldEHFrameSecInfo.FileAddress + OldEHFrameSecInfo.Size
- EHFrameSecInfo.FileAddress;
EFMM->SectionMapInfo.erase(OldSMII);
const auto EHFrameSectionSize = (OldEHFrameSection->getFileAddress() +
OldEHFrameSection->getOutputSize() -
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 "
<< EHFrameSecInfo.Size << '\n');
<< EHFrameSection->getOutputSize() << '\n');
}
uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const {
@ -4100,11 +4104,8 @@ bool RewriteInstance::willOverwriteSection(StringRef SectionName) {
return true;
}
auto SMII = EFMM->SectionMapInfo.find(SectionName);
if (SMII != EFMM->SectionMapInfo.end())
return true;
return false;
auto Section = BC->getUniqueSectionByName(SectionName);
return Section && Section->isAllocatable() && Section->isFinalized();
}
BinaryFunction *

View File

@ -39,43 +39,6 @@ class CFIReaderWriter;
class DataAggregator;
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 {
uint64_t Address; /// Address of the segment in memory.
uint64_t Size; /// Size of the segment in memory.
@ -105,20 +68,15 @@ private:
StringRef SectionName,
bool IsCode,
bool IsReadOnly);
BinaryContext &BC;
bool AllowStubs;
public:
/// [start memory address] -> [segment info] mapping.
std::map<uint64_t, SegmentInfo> SegmentMapInfo;
/// Keep [section name] -> [section info] map for later remapping.
std::map<std::string, SectionInfo> SectionMapInfo;
/// Information about non-allocatable sections.
std::map<std::string, SectionInfo> NoteSectionInfo;
ExecutableFileMemoryManager(bool AllowStubs) : AllowStubs(AllowStubs) {}
ExecutableFileMemoryManager(BinaryContext &BC, bool AllowStubs)
: BC(BC), AllowStubs(AllowStubs) {}
~ExecutableFileMemoryManager();
@ -202,7 +160,7 @@ public:
/// non-empty.
void emitDataSection(MCStreamer *Streamer,
const BinarySection &Section,
std::string Name = "");
StringRef Name = StringRef());
/// Emit data sections that have code references in them.
void emitDataSections(MCStreamer *Streamer);
@ -312,7 +270,7 @@ private:
void rewriteNoteSections();
/// Write .eh_frame_hdr.
void writeEHFrameHeader(SectionInfo &EHFrameSecInfo);
void writeEHFrameHeader();
/// Disassemble and create function entries for PLT.
void disassemblePLT();