diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -526,6 +526,10 @@ /// accordingly. void adjustCodePadding(); + /// Verify unclaimed Data to Code relocations, creating secondary entry points + /// for targets. + void postProcessDataRelocations(); + /// Regular page size. unsigned RegularPageSize{0x1000}; static constexpr unsigned RegularPageSizeX86 = 0x1000; diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -16,6 +16,7 @@ #include "bolt/Utils/CommandLineOpts.h" #include "bolt/Utils/NameResolver.h" #include "bolt/Utils/Utils.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" @@ -991,6 +992,81 @@ } } +void BinaryContext::postProcessDataRelocations() { + if (!HasRelocations) + return; + + SmallPtrSet Functions; + SmallPtrSet EntryPoints; + + for (BinarySection &Section : sections()) { + const uint64_t SourceSectionStart = Section.getAddress(); + for (const Relocation &Rel : Section.relocations()) { + LLVM_DEBUG({ + dbgs() << "BOLT-DEBUG: post-processing relocation "; + Rel.print(dbgs()); + dbgs() << '\n'; + }); + // PC-relative relocations have separate checking mechanism (strict mode) + if (Relocation::isPCRelative(Rel.Type)) + continue; + + // We expect relocations against function local labels, which have + // Addend == 0. + if (Rel.Addend) + continue; + + const MCSymbol *ReferencedSymbol = Rel.Symbol; + // Check if the relocation value is a function entry point + if (getFunctionForSymbol(ReferencedSymbol)) + continue; + + // Check if the relocation value is a recognized jump table target + const uint64_t RelValue = Rel.Value; + const uint64_t RelSourceAddress = SourceSectionStart + Rel.Offset; + BinaryFunction *BF = getBinaryFunctionContainingAddress( + RelValue, /* CheckPastEnd */ false, /* UseMaxSize */ false); + + // If there's no function at RelValue address, no need to register the + // target symbol as an entry point - i.e. checking past function end. + if (!BF) + continue; + + // Skip non-simple functions + if (!BF->isSimple()) + continue; + + const JumpTable *JT = BF->getJumpTableContainingAddress(RelSourceAddress); + if (JT && llvm::is_contained(JT->Entries, ReferencedSymbol)) + continue; + + // Otherwise register the relocation target as a secondary entry point + const BinaryBasicBlock *BB = BF->getBasicBlockForLabel(ReferencedSymbol); + const MCSymbol *Label = BF->addEntryPoint(*BB); + + Functions.insert(BF); + EntryPoints.insert(Label); + LLVM_DEBUG({ + dbgs() << "BOLT-DEBUG: registered " << BB->getName() + << " as a secondary entry point in function " << *BF << '\n'; + }); + } + } + for (BinaryFunction *BF : Functions) + BF->setSimple(false); + if (opts::Verbosity >= 1) { + outs() << "BOLT-INFO: created " << EntryPoints.size() << " secondary entry " + << "points in " << Functions.size() << " functions for unclaimed " + << "data to code relocations.\n"; + if (opts::Verbosity >= 2) { + for (BinaryFunction *BF : Functions) + outs() << *BF << '\n'; + for (const MCSymbol *Symbol : EntryPoints) + outs() << Symbol->getName() << '\n'; + } + } +} + MCSymbol *BinaryContext::registerNameAtAddress(StringRef Name, uint64_t Address, uint64_t Size, uint16_t Alignment, diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -2931,6 +2931,7 @@ /*ForceSequential*/ opts::SequentialDisassembly || opts::PrintAll); BC->postProcessSymbolTable(); + BC->postProcessDataRelocations(); } void RewriteInstance::postProcessFunctions() {