mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[BOLT] Fix -jump-tables=basic in relocation mode.
Summary: In a prev diff I added an option to update jump tables in-place (on by default) and accidentally broke the default handling of jump tables in relocation mode. The update should be happening semi-automatically, but because we ignore relocations for jump tables it wasn't happening (derp). Since we mostly use '-jump-tables=move' this hasn't been noticed for some time. This diff gets rid of IgnoredRelocations and removes relocations from a relocation set when they are no longer needed. If relocations are created later for jump tables they are no longer ignored. (cherry picked from FBD4595159)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
@@ -415,14 +416,107 @@ ErrorOr<SectionRef> BinaryContext::getSectionForAddress(uint64_t Address) const{
|
||||
return std::make_error_code(std::errc::bad_address);
|
||||
}
|
||||
|
||||
void BinaryContext::addSectionRelocation(SectionRef Section, uint64_t Address,
|
||||
void BinaryContext::addSectionRelocation(SectionRef Section, uint64_t Offset,
|
||||
MCSymbol *Symbol, uint64_t Type,
|
||||
uint64_t Addend) {
|
||||
auto RI = SectionRelocations.find(Section);
|
||||
if (RI == SectionRelocations.end()) {
|
||||
auto Result =
|
||||
SectionRelocations.emplace(Section, std::vector<Relocation>());
|
||||
SectionRelocations.emplace(Section, std::set<Relocation>());
|
||||
RI = Result.first;
|
||||
}
|
||||
RI->second.emplace_back(Relocation{Address, Symbol, Type, Addend});
|
||||
RI->second.emplace(Relocation{Offset, Symbol, Type, Addend});
|
||||
}
|
||||
|
||||
void BinaryContext::addRelocation(uint64_t Address, MCSymbol *Symbol,
|
||||
uint64_t Type, uint64_t Addend) {
|
||||
auto ContainingSection = getSectionForAddress(Address);
|
||||
assert(ContainingSection && "cannot find section for address");
|
||||
addSectionRelocation(*ContainingSection,
|
||||
Address - ContainingSection->getAddress(),
|
||||
Symbol,
|
||||
Type,
|
||||
Addend);
|
||||
}
|
||||
|
||||
void BinaryContext::removeRelocationAt(uint64_t Address) {
|
||||
auto ContainingSection = getSectionForAddress(Address);
|
||||
assert(ContainingSection && "cannot find section for address");
|
||||
auto RI = SectionRelocations.find(*ContainingSection);
|
||||
if (RI == SectionRelocations.end())
|
||||
return;
|
||||
|
||||
auto &Relocations = RI->second;
|
||||
auto RelocI = Relocations.find(
|
||||
Relocation{Address - ContainingSection->getAddress(), 0, 0, 0, 0});
|
||||
if (RelocI == Relocations.end())
|
||||
return;
|
||||
|
||||
Relocations.erase(RelocI);
|
||||
}
|
||||
|
||||
size_t Relocation::getSizeForType(uint64_t Type) {
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation type");
|
||||
case ELF::R_X86_64_PC8:
|
||||
return 1;
|
||||
case ELF::R_X86_64_PLT32:
|
||||
case ELF::R_X86_64_PC32:
|
||||
case ELF::R_X86_64_32S:
|
||||
case ELF::R_X86_64_32:
|
||||
case ELF::R_X86_64_GOTPCREL:
|
||||
case ELF::R_X86_64_GOTTPOFF:
|
||||
case ELF::R_X86_64_TPOFF32:
|
||||
case ELF::R_X86_64_GOTPCRELX:
|
||||
case ELF::R_X86_64_REX_GOTPCRELX:
|
||||
return 4;
|
||||
case ELF::R_X86_64_PC64:
|
||||
case ELF::R_X86_64_64:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
bool Relocation::isPCRelative(uint64_t Type) {
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("Unknown relocation type");
|
||||
|
||||
case ELF::R_X86_64_64:
|
||||
case ELF::R_X86_64_32:
|
||||
case ELF::R_X86_64_32S:
|
||||
case ELF::R_X86_64_TPOFF32:
|
||||
return false;
|
||||
|
||||
case ELF::R_X86_64_PC8:
|
||||
case ELF::R_X86_64_PC32:
|
||||
case ELF::R_X86_64_GOTPCREL:
|
||||
case ELF::R_X86_64_PLT32:
|
||||
case ELF::R_X86_64_GOTTPOFF:
|
||||
case ELF::R_X86_64_GOTPCRELX:
|
||||
case ELF::R_X86_64_REX_GOTPCRELX:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Relocation::emit(MCStreamer *Streamer) const {
|
||||
const auto Size = getSizeForType(Type);
|
||||
auto &Ctx = Streamer->getContext();
|
||||
if (isPCRelative(Type)) {
|
||||
auto *TempLabel = Ctx.createTempSymbol();
|
||||
Streamer->EmitLabel(TempLabel);
|
||||
auto Value =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(Symbol, Ctx),
|
||||
MCSymbolRefExpr::create(TempLabel, Ctx),
|
||||
Ctx);
|
||||
if (Addend) {
|
||||
Value = MCBinaryExpr::createAdd(Value,
|
||||
MCConstantExpr::create(Addend, Ctx),
|
||||
Ctx);
|
||||
}
|
||||
Streamer->EmitValue(Value, Size);
|
||||
} else {
|
||||
Streamer->EmitSymbolValue(Symbol, Size);
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class DataReader;
|
||||
/// Relocation class.
|
||||
struct Relocation {
|
||||
uint64_t Offset;
|
||||
MCSymbol *Symbol;
|
||||
mutable MCSymbol *Symbol; /// mutable to allow modification by emitter.
|
||||
uint64_t Type;
|
||||
uint64_t Addend;
|
||||
uint64_t Value;
|
||||
@@ -69,7 +69,7 @@ struct Relocation {
|
||||
|
||||
/// Emit relocation at a current \p Streamer' position. The caller is
|
||||
/// responsible for setting the position correctly.
|
||||
size_t emit(MCStreamer *Streamer);
|
||||
size_t emit(MCStreamer *Streamer) const;
|
||||
};
|
||||
|
||||
/// Relocation ordering by offset.
|
||||
@@ -109,14 +109,8 @@ public:
|
||||
/// List of DWARF location lists in .debug_loc.
|
||||
std::vector<LocationList> LocationLists;
|
||||
|
||||
/// List of relocation offsets where relocations should be ignored.
|
||||
std::set<uint64_t> IgnoredRelocations;
|
||||
|
||||
/// List of PC-relative relocations from data to code.
|
||||
std::set<uint64_t> PCRelativeDataRelocations;
|
||||
|
||||
/// Section relocations.
|
||||
std::map<SectionRef, std::vector<Relocation>> SectionRelocations;
|
||||
std::map<SectionRef, std::set<Relocation>> SectionRelocations;
|
||||
|
||||
/// List of DWARF entries in .debug_info that have address ranges to be
|
||||
/// updated. These include lexical blocks (DW_TAG_lexical_block) and concrete
|
||||
@@ -231,11 +225,18 @@ public:
|
||||
BinaryFunction &ParentBF,
|
||||
std::map<uint64_t, BinaryFunction> &BFs);
|
||||
|
||||
/// Add section relocation.
|
||||
void addSectionRelocation(SectionRef Section, uint64_t Address,
|
||||
/// Add relocation for \p Section at a given \p Offset.
|
||||
void addSectionRelocation(SectionRef 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,
|
||||
uint64_t Addend = 0);
|
||||
|
||||
/// Remove registered relocation at a given \p Address.
|
||||
void removeRelocationAt(uint64_t Address);
|
||||
|
||||
const BinaryFunction *getFunctionForSymbol(const MCSymbol *Symbol) const {
|
||||
auto BFI = SymbolToFunctionMap.find(Symbol);
|
||||
return BFI == SymbolToFunctionMap.end() ? nullptr : BFI->second;
|
||||
|
||||
@@ -1261,9 +1261,9 @@ void BinaryFunction::postProcessJumpTables() {
|
||||
if (TargetOffset < getSize())
|
||||
TakenBranches.emplace_back(JTSiteOffset, TargetOffset);
|
||||
|
||||
// Ignore relocations for jump tables.
|
||||
// Take ownership of jump table relocations.
|
||||
if (opts::Relocs)
|
||||
BC.IgnoredRelocations.emplace(JT->Address + EntryOffset);
|
||||
BC.removeRelocationAt(JT->Address + EntryOffset);
|
||||
|
||||
EntryOffset += JT->EntrySize;
|
||||
|
||||
@@ -3821,71 +3821,5 @@ void DynoStats::operator+=(const DynoStats &Other) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t Relocation::getSizeForType(uint64_t Type) {
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("unsupported relocation type");
|
||||
case ELF::R_X86_64_PC8:
|
||||
return 1;
|
||||
case ELF::R_X86_64_PLT32:
|
||||
case ELF::R_X86_64_PC32:
|
||||
case ELF::R_X86_64_32S:
|
||||
case ELF::R_X86_64_32:
|
||||
case ELF::R_X86_64_GOTPCREL:
|
||||
case ELF::R_X86_64_GOTTPOFF:
|
||||
case ELF::R_X86_64_TPOFF32:
|
||||
case ELF::R_X86_64_GOTPCRELX:
|
||||
case ELF::R_X86_64_REX_GOTPCRELX:
|
||||
return 4;
|
||||
case ELF::R_X86_64_PC64:
|
||||
case ELF::R_X86_64_64:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
bool Relocation::isPCRelative(uint64_t Type) {
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("Unknown relocation type");
|
||||
|
||||
case ELF::R_X86_64_64:
|
||||
case ELF::R_X86_64_32:
|
||||
case ELF::R_X86_64_32S:
|
||||
case ELF::R_X86_64_TPOFF32:
|
||||
return false;
|
||||
|
||||
case ELF::R_X86_64_PC8:
|
||||
case ELF::R_X86_64_PC32:
|
||||
case ELF::R_X86_64_GOTPCREL:
|
||||
case ELF::R_X86_64_PLT32:
|
||||
case ELF::R_X86_64_GOTTPOFF:
|
||||
case ELF::R_X86_64_GOTPCRELX:
|
||||
case ELF::R_X86_64_REX_GOTPCRELX:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Relocation::emit(MCStreamer *Streamer) {
|
||||
const auto Size = getSizeForType(Type);
|
||||
auto &Ctx = Streamer->getContext();
|
||||
if (isPCRelative(Type)) {
|
||||
auto *TempLabel = Ctx.createTempSymbol();
|
||||
Streamer->EmitLabel(TempLabel);
|
||||
auto Value =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(Symbol, Ctx),
|
||||
MCSymbolRefExpr::create(TempLabel, Ctx),
|
||||
Ctx);
|
||||
if (Addend) {
|
||||
Value = MCBinaryExpr::createAdd(Value,
|
||||
MCConstantExpr::create(Addend, Ctx),
|
||||
Ctx);
|
||||
}
|
||||
Streamer->EmitValue(Value, Size);
|
||||
} else {
|
||||
Streamer->EmitSymbolValue(Symbol, Size);
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
} // namespace bolt
|
||||
} // namespace llvm
|
||||
|
||||
@@ -1494,8 +1494,6 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
|
||||
// from linker data alone.
|
||||
if (IsFromCode) {
|
||||
ContainingBF->addPCRelativeRelocationAddress(Rel.getOffset());
|
||||
} else {
|
||||
BC->PCRelativeDataRelocations.emplace(Rel.getOffset());
|
||||
}
|
||||
DEBUG(dbgs() << "BOLT-DEBUG: not creating PC-relative relocation\n");
|
||||
continue;
|
||||
@@ -1551,14 +1549,8 @@ void RewriteInstance::readRelocations(const SectionRef &Section) {
|
||||
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from code to data\n");
|
||||
}
|
||||
} else if (ToCode) {
|
||||
auto ContainingSection = BC->getSectionForAddress(Rel.getOffset());
|
||||
assert(ContainingSection && "cannot find section for address");
|
||||
assert(Addend == 0 && "did not expect addend");
|
||||
BC->addSectionRelocation(*ContainingSection,
|
||||
Rel.getOffset()- ContainingSection->getAddress(),
|
||||
ReferencedSymbol,
|
||||
Rel.getType());
|
||||
|
||||
BC->addRelocation(Rel.getOffset(), ReferencedSymbol, Rel.getType());
|
||||
} else {
|
||||
DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n");
|
||||
}
|
||||
@@ -1998,21 +1990,6 @@ void RewriteInstance::emitFunctions() {
|
||||
}
|
||||
|
||||
if (opts::Relocs) {
|
||||
// Make sure all original PC-relative relocations from data are ignored.
|
||||
std::vector<uint64_t> MissedAddresses;
|
||||
std::set_difference(BC->PCRelativeDataRelocations.begin(),
|
||||
BC->PCRelativeDataRelocations.end(),
|
||||
BC->IgnoredRelocations.begin(),
|
||||
BC->IgnoredRelocations.end(),
|
||||
std::back_inserter(MissedAddresses));
|
||||
|
||||
if (!MissedAddresses.empty()) {
|
||||
errs() << "BOLT-ERROR: " << MissedAddresses.size()
|
||||
<< " missed addresses:\n";
|
||||
for (auto Address : MissedAddresses)
|
||||
errs() << "\t0x" << Twine::utohexstr(Address) << '\n';
|
||||
}
|
||||
|
||||
emitDataSections(Streamer.get());
|
||||
}
|
||||
|
||||
@@ -2324,12 +2301,7 @@ void RewriteInstance::emitDataSection(MCStreamer *Streamer, SectionRef Section,
|
||||
|
||||
auto &Relocations = SRI->second;
|
||||
uint64_t SectionOffset = 0;
|
||||
std::sort(Relocations.begin(), Relocations.end());
|
||||
for (auto &Relocation : Relocations) {
|
||||
auto RelocationAddress = Section.getAddress() + Relocation.Offset;
|
||||
if (BC->IgnoredRelocations.count(RelocationAddress)) {
|
||||
continue;
|
||||
}
|
||||
assert(Relocation.Offset < Section.getSize() && "overflow detected");
|
||||
if (SectionOffset < Relocation.Offset) {
|
||||
Streamer->EmitBytes(
|
||||
|
||||
Reference in New Issue
Block a user