[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:
Maksim Panchenko
2017-02-21 16:15:15 -08:00
parent 88244a10bb
commit d3e33b6edc
4 changed files with 112 additions and 111 deletions

View File

@@ -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;
}

View File

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

View File

@@ -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

View File

@@ -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(