forked from OSchip/llvm-project
[BOLT][AArch64] Handle gold linker veneers
The gold linker veneers are written between functions without symbols, so we to handle it specially in BOLT. Vladislav Khmelevsky, Advanced Software Technology Lab, Huawei Differential Revision: https://reviews.llvm.org/D129260
This commit is contained in:
parent
f827b4b657
commit
35efe1d806
|
@ -39,6 +39,7 @@
|
|||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <shared_mutex>
|
||||
|
@ -641,6 +642,10 @@ public:
|
|||
/// special linux kernel sections
|
||||
std::unordered_map<uint64_t, std::vector<LKInstructionMarkerInfo>> LKMarkers;
|
||||
|
||||
/// List of external addresses in the code that are not a function start
|
||||
/// and are referenced from BinaryFunction.
|
||||
std::list<std::pair<BinaryFunction *, uint64_t>> InterproceduralReferences;
|
||||
|
||||
/// PseudoProbe decoder
|
||||
MCPseudoProbeDecoder ProbeDecoder;
|
||||
|
||||
|
@ -884,8 +889,23 @@ public:
|
|||
bool registerFragment(BinaryFunction &TargetFunction,
|
||||
BinaryFunction &Function) const;
|
||||
|
||||
/// Resolve inter-procedural dependencies from \p Function.
|
||||
void processInterproceduralReferences(BinaryFunction &Function);
|
||||
/// Add unterprocedural reference for \p Function to \p Address
|
||||
void addInterproceduralReference(BinaryFunction *Function, uint64_t Address) {
|
||||
InterproceduralReferences.push_back({Function, Address});
|
||||
}
|
||||
|
||||
/// Used to fix the target of linker-generated AArch64 adrp + add
|
||||
/// sequence with no relocation info.
|
||||
void addAdrpAddRelocAArch64(BinaryFunction &BF, MCInst &LoadLowBits,
|
||||
MCInst &LoadHiBits, uint64_t Target);
|
||||
|
||||
/// Return true if AARch64 veneer was successfully matched at a given
|
||||
/// \p Address and register veneer binary function if \p MatchOnly
|
||||
/// argument is false.
|
||||
bool handleAArch64Veneer(uint64_t Address, bool MatchOnly = false);
|
||||
|
||||
/// Resolve inter-procedural dependencies from
|
||||
void processInterproceduralReferences();
|
||||
|
||||
/// Skip functions with all parent and child fragments transitively.
|
||||
void skipMarkedFragments();
|
||||
|
|
|
@ -253,10 +253,6 @@ private:
|
|||
|
||||
std::unique_ptr<BinaryLoopInfo> BLI;
|
||||
|
||||
/// Set of external addresses in the code that are not a function start
|
||||
/// and are referenced from this function.
|
||||
std::set<uint64_t> InterproceduralReferences;
|
||||
|
||||
/// All labels in the function that are referenced via relocations from
|
||||
/// data objects. Typically these are jump table destinations and computed
|
||||
/// goto labels.
|
||||
|
|
|
@ -1384,7 +1384,7 @@ public:
|
|||
llvm_unreachable("not implemented");
|
||||
}
|
||||
|
||||
/// Return true if the instruction CurInst, in combination with the recent
|
||||
/// Return not 0 if the instruction CurInst, in combination with the recent
|
||||
/// history of disassembled instructions supplied by [Begin, End), is a linker
|
||||
/// generated veneer/stub that needs patching. This happens in AArch64 when
|
||||
/// the code is large and the linker needs to generate stubs, but it does
|
||||
|
@ -1394,11 +1394,14 @@ public:
|
|||
/// is put in TgtLowBits, and its pair in TgtHiBits. If the instruction in
|
||||
/// TgtHiBits does not have an immediate operand, but an expression, then
|
||||
/// this expression is put in TgtHiSym and Tgt only contains the lower bits.
|
||||
virtual bool matchLinkerVeneer(InstructionIterator Begin,
|
||||
InstructionIterator End, uint64_t Address,
|
||||
const MCInst &CurInst, MCInst *&TargetHiBits,
|
||||
MCInst *&TargetLowBits,
|
||||
uint64_t &Target) const {
|
||||
/// Return value is a total number of instructions that were used to create
|
||||
/// a veneer.
|
||||
virtual uint64_t matchLinkerVeneer(InstructionIterator Begin,
|
||||
InstructionIterator End, uint64_t Address,
|
||||
const MCInst &CurInst,
|
||||
MCInst *&TargetHiBits,
|
||||
MCInst *&TargetLowBits,
|
||||
uint64_t &Target) const {
|
||||
llvm_unreachable("not implemented");
|
||||
}
|
||||
|
||||
|
|
|
@ -415,7 +415,7 @@ BinaryContext::handleAddressRef(uint64_t Address, BinaryFunction &BF,
|
|||
BF.addEntryPointAtOffset(Address - BF.getAddress()), Addend);
|
||||
}
|
||||
} else {
|
||||
BF.InterproceduralReferences.insert(Address);
|
||||
addInterproceduralReference(&BF, Address);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1120,9 +1120,106 @@ bool BinaryContext::registerFragment(BinaryFunction &TargetFunction,
|
|||
return true;
|
||||
}
|
||||
|
||||
void BinaryContext::processInterproceduralReferences(BinaryFunction &Function) {
|
||||
for (uint64_t Address : Function.InterproceduralReferences) {
|
||||
if (!Address)
|
||||
void BinaryContext::addAdrpAddRelocAArch64(BinaryFunction &BF,
|
||||
MCInst &LoadLowBits,
|
||||
MCInst &LoadHiBits,
|
||||
uint64_t Target) {
|
||||
const MCSymbol *TargetSymbol;
|
||||
uint64_t Addend = 0;
|
||||
std::tie(TargetSymbol, Addend) = handleAddressRef(Target, BF,
|
||||
/*IsPCRel*/ true);
|
||||
int64_t Val;
|
||||
MIB->replaceImmWithSymbolRef(LoadHiBits, TargetSymbol, Addend, Ctx.get(), Val,
|
||||
ELF::R_AARCH64_ADR_PREL_PG_HI21);
|
||||
MIB->replaceImmWithSymbolRef(LoadLowBits, TargetSymbol, Addend, Ctx.get(),
|
||||
Val, ELF::R_AARCH64_ADD_ABS_LO12_NC);
|
||||
}
|
||||
|
||||
bool BinaryContext::handleAArch64Veneer(uint64_t Address, bool MatchOnly) {
|
||||
BinaryFunction *TargetFunction = getBinaryFunctionContainingAddress(Address);
|
||||
if (TargetFunction)
|
||||
return false;
|
||||
|
||||
ErrorOr<BinarySection &> Section = getSectionForAddress(Address);
|
||||
assert(Section && "cannot get section for referenced address");
|
||||
if (!Section->isText())
|
||||
return false;
|
||||
|
||||
bool Ret = false;
|
||||
StringRef SectionContents = Section->getContents();
|
||||
uint64_t Offset = Address - Section->getAddress();
|
||||
const uint64_t MaxSize = SectionContents.size() - Offset;
|
||||
const uint8_t *Bytes =
|
||||
reinterpret_cast<const uint8_t *>(SectionContents.data());
|
||||
ArrayRef<uint8_t> Data(Bytes + Offset, MaxSize);
|
||||
|
||||
auto matchVeneer = [&](BinaryFunction::InstrMapType &Instructions,
|
||||
MCInst &Instruction, uint64_t Offset,
|
||||
uint64_t AbsoluteInstrAddr,
|
||||
uint64_t TotalSize) -> bool {
|
||||
MCInst *TargetHiBits, *TargetLowBits;
|
||||
uint64_t TargetAddress, Count;
|
||||
Count = MIB->matchLinkerVeneer(Instructions.begin(), Instructions.end(),
|
||||
AbsoluteInstrAddr, Instruction, TargetHiBits,
|
||||
TargetLowBits, TargetAddress);
|
||||
if (!Count)
|
||||
return false;
|
||||
|
||||
if (MatchOnly)
|
||||
return true;
|
||||
|
||||
// NOTE The target symbol was created during disassemble's
|
||||
// handleExternalReference
|
||||
const MCSymbol *VeneerSymbol = getOrCreateGlobalSymbol(Address, "FUNCat");
|
||||
BinaryFunction *Veneer = createBinaryFunction(VeneerSymbol->getName().str(),
|
||||
*Section, Address, TotalSize);
|
||||
addAdrpAddRelocAArch64(*Veneer, *TargetLowBits, *TargetHiBits,
|
||||
TargetAddress);
|
||||
MIB->addAnnotation(Instruction, "AArch64Veneer", true);
|
||||
Veneer->addInstruction(Offset, std::move(Instruction));
|
||||
--Count;
|
||||
for (auto It = std::prev(Instructions.end()); Count != 0;
|
||||
It = std::prev(It), --Count) {
|
||||
MIB->addAnnotation(It->second, "AArch64Veneer", true);
|
||||
Veneer->addInstruction(It->first, std::move(It->second));
|
||||
}
|
||||
|
||||
Veneer->getOrCreateLocalLabel(Address);
|
||||
Veneer->setMaxSize(TotalSize);
|
||||
Veneer->updateState(BinaryFunction::State::Disassembled);
|
||||
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: handling veneer function at 0x" << Address
|
||||
<< "\n");
|
||||
return true;
|
||||
};
|
||||
|
||||
uint64_t Size = 0, TotalSize = 0;
|
||||
BinaryFunction::InstrMapType VeneerInstructions;
|
||||
for (Offset = 0; Offset < MaxSize; Offset += Size) {
|
||||
MCInst Instruction;
|
||||
const uint64_t AbsoluteInstrAddr = Address + Offset;
|
||||
if (!SymbolicDisAsm->getInstruction(Instruction, Size, Data.slice(Offset),
|
||||
AbsoluteInstrAddr, nulls()))
|
||||
break;
|
||||
|
||||
TotalSize += Size;
|
||||
if (MIB->isBranch(Instruction)) {
|
||||
Ret = matchVeneer(VeneerInstructions, Instruction, Offset,
|
||||
AbsoluteInstrAddr, TotalSize);
|
||||
break;
|
||||
}
|
||||
|
||||
VeneerInstructions.emplace(Offset, std::move(Instruction));
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
void BinaryContext::processInterproceduralReferences() {
|
||||
for (const std::pair<BinaryFunction *, uint64_t> &It :
|
||||
InterproceduralReferences) {
|
||||
BinaryFunction &Function = *It.first;
|
||||
uint64_t Address = It.second;
|
||||
if (!Address || Function.isIgnored())
|
||||
continue;
|
||||
|
||||
BinaryFunction *TargetFunction =
|
||||
|
@ -1131,7 +1228,7 @@ void BinaryContext::processInterproceduralReferences(BinaryFunction &Function) {
|
|||
continue;
|
||||
|
||||
if (TargetFunction) {
|
||||
if (TargetFunction->IsFragment &&
|
||||
if (TargetFunction->isFragment() &&
|
||||
!registerFragment(*TargetFunction, Function)) {
|
||||
errs() << "BOLT-WARNING: interprocedural reference between unrelated "
|
||||
"fragments: "
|
||||
|
@ -1157,6 +1254,10 @@ void BinaryContext::processInterproceduralReferences(BinaryFunction &Function) {
|
|||
if (SectionName == ".plt" || SectionName == ".plt.got")
|
||||
continue;
|
||||
|
||||
// Check if it is aarch64 veneer written at Address
|
||||
if (isAArch64() && handleAArch64Veneer(Address))
|
||||
continue;
|
||||
|
||||
if (opts::processAllFunctions()) {
|
||||
errs() << "BOLT-ERROR: cannot process binaries with unmarked "
|
||||
<< "object in code at address 0x" << Twine::utohexstr(Address)
|
||||
|
@ -1177,7 +1278,7 @@ void BinaryContext::processInterproceduralReferences(BinaryFunction &Function) {
|
|||
}
|
||||
}
|
||||
|
||||
clearList(Function.InterproceduralReferences);
|
||||
InterproceduralReferences.clear();
|
||||
}
|
||||
|
||||
void BinaryContext::postProcessSymbolTable() {
|
||||
|
|
|
@ -1061,27 +1061,12 @@ bool BinaryFunction::disassemble() {
|
|||
Instruction, Expr, *BC.Ctx, 0)));
|
||||
};
|
||||
|
||||
// Used to fix the target of linker-generated AArch64 stubs with no relocation
|
||||
// info
|
||||
auto fixStubTarget = [&](MCInst &LoadLowBits, MCInst &LoadHiBits,
|
||||
uint64_t Target) {
|
||||
const MCSymbol *TargetSymbol;
|
||||
uint64_t Addend = 0;
|
||||
std::tie(TargetSymbol, Addend) = BC.handleAddressRef(Target, *this, true);
|
||||
|
||||
int64_t Val;
|
||||
MIB->replaceImmWithSymbolRef(LoadHiBits, TargetSymbol, Addend, Ctx.get(),
|
||||
Val, ELF::R_AARCH64_ADR_PREL_PG_HI21);
|
||||
MIB->replaceImmWithSymbolRef(LoadLowBits, TargetSymbol, Addend, Ctx.get(),
|
||||
Val, ELF::R_AARCH64_ADD_ABS_LO12_NC);
|
||||
};
|
||||
|
||||
auto handleExternalReference = [&](MCInst &Instruction, uint64_t Size,
|
||||
uint64_t Offset, uint64_t TargetAddress,
|
||||
bool &IsCall) -> MCSymbol * {
|
||||
const uint64_t AbsoluteInstrAddr = getAddress() + Offset;
|
||||
MCSymbol *TargetSymbol = nullptr;
|
||||
InterproceduralReferences.insert(TargetAddress);
|
||||
BC.addInterproceduralReference(this, TargetAddress);
|
||||
if (opts::Verbosity >= 2 && !IsCall && Size == 2 && !BC.HasRelocations) {
|
||||
errs() << "BOLT-WARNING: relaxed tail call detected at 0x"
|
||||
<< Twine::utohexstr(AbsoluteInstrAddr) << " in function " << *this
|
||||
|
@ -1147,7 +1132,7 @@ bool BinaryFunction::disassemble() {
|
|||
HasFixedIndirectBranch = true;
|
||||
} else {
|
||||
MIB->convertJmpToTailCall(Instruction);
|
||||
InterproceduralReferences.insert(IndirectTarget);
|
||||
BC.addInterproceduralReference(this, IndirectTarget);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1164,19 +1149,20 @@ bool BinaryFunction::disassemble() {
|
|||
auto handleAArch64IndirectCall = [&](MCInst &Instruction, uint64_t Offset) {
|
||||
const uint64_t AbsoluteInstrAddr = getAddress() + Offset;
|
||||
MCInst *TargetHiBits, *TargetLowBits;
|
||||
uint64_t TargetAddress;
|
||||
if (MIB->matchLinkerVeneer(Instructions.begin(), Instructions.end(),
|
||||
AbsoluteInstrAddr, Instruction, TargetHiBits,
|
||||
TargetLowBits, TargetAddress)) {
|
||||
uint64_t TargetAddress, Count;
|
||||
Count = MIB->matchLinkerVeneer(Instructions.begin(), Instructions.end(),
|
||||
AbsoluteInstrAddr, Instruction, TargetHiBits,
|
||||
TargetLowBits, TargetAddress);
|
||||
if (Count) {
|
||||
MIB->addAnnotation(Instruction, "AArch64Veneer", true);
|
||||
|
||||
uint8_t Counter = 0;
|
||||
for (auto It = std::prev(Instructions.end()); Counter != 2;
|
||||
--It, ++Counter) {
|
||||
--Count;
|
||||
for (auto It = std::prev(Instructions.end()); Count != 0;
|
||||
It = std::prev(It), --Count) {
|
||||
MIB->addAnnotation(It->second, "AArch64Veneer", true);
|
||||
}
|
||||
|
||||
fixStubTarget(*TargetLowBits, *TargetHiBits, TargetAddress);
|
||||
BC.addAdrpAddRelocAArch64(*this, *TargetLowBits, *TargetHiBits,
|
||||
TargetAddress);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1295,7 +1281,9 @@ bool BinaryFunction::disassemble() {
|
|||
TargetSymbol = getOrCreateLocalLabel(TargetAddress);
|
||||
} else {
|
||||
if (TargetAddress == getAddress() + getSize() &&
|
||||
TargetAddress < getAddress() + getMaxSize()) {
|
||||
TargetAddress < getAddress() + getMaxSize() &&
|
||||
!(BC.isAArch64() &&
|
||||
BC.handleAArch64Veneer(TargetAddress, /*MatchOnly*/ true))) {
|
||||
// Result of __builtin_unreachable().
|
||||
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: jump past end detected at 0x"
|
||||
<< Twine::utohexstr(AbsoluteInstrAddr)
|
||||
|
@ -2842,7 +2830,6 @@ void BinaryFunction::clearDisasmState() {
|
|||
clearList(Instructions);
|
||||
clearList(IgnoredBranches);
|
||||
clearList(TakenBranches);
|
||||
clearList(InterproceduralReferences);
|
||||
|
||||
if (BC.HasRelocations) {
|
||||
for (std::pair<const uint32_t, MCSymbol *> &LI : Labels)
|
||||
|
@ -4423,17 +4410,20 @@ void BinaryFunction::printLoopInfo(raw_ostream &OS) const {
|
|||
}
|
||||
|
||||
bool BinaryFunction::isAArch64Veneer() const {
|
||||
if (BasicBlocks.size() != 1)
|
||||
if (empty())
|
||||
return false;
|
||||
|
||||
BinaryBasicBlock &BB = **BasicBlocks.begin();
|
||||
if (BB.size() != 3)
|
||||
return false;
|
||||
|
||||
for (MCInst &Inst : BB)
|
||||
if (!BC.MIB->hasAnnotation(Inst, "AArch64Veneer"))
|
||||
return false;
|
||||
|
||||
for (auto I = BasicBlocks.begin() + 1, E = BasicBlocks.end(); I != E; ++I) {
|
||||
for (MCInst &Inst : **I)
|
||||
if (!BC.MIB->isNoop(Inst))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1595,6 +1595,9 @@ void InstructionLowering::runOnFunctions(BinaryContext &BC) {
|
|||
}
|
||||
|
||||
void StripRepRet::runOnFunctions(BinaryContext &BC) {
|
||||
if (!BC.isX86())
|
||||
return;
|
||||
|
||||
uint64_t NumPrefixesRemoved = 0;
|
||||
uint64_t NumBytesSaved = 0;
|
||||
for (auto &BFI : BC.getBinaryFunctions()) {
|
||||
|
|
|
@ -33,44 +33,35 @@ void VeneerElimination::runOnFunctions(BinaryContext &BC) {
|
|||
if (!opts::EliminateVeneers || !BC.isAArch64())
|
||||
return;
|
||||
|
||||
auto &BFs = BC.getBinaryFunctions();
|
||||
std::map<uint64_t, BinaryFunction> &BFs = BC.getBinaryFunctions();
|
||||
std::unordered_map<const MCSymbol *, const MCSymbol *> VeneerDestinations;
|
||||
uint64_t VeneersCount = 0;
|
||||
for (auto It = BFs.begin(); It != BFs.end();) {
|
||||
auto CurrentIt = It;
|
||||
++It;
|
||||
for (auto &It : BFs) {
|
||||
BinaryFunction &VeneerFunction = It.second;
|
||||
if (!VeneerFunction.isAArch64Veneer())
|
||||
continue;
|
||||
|
||||
if (CurrentIt->second.isAArch64Veneer()) {
|
||||
VeneersCount++;
|
||||
BinaryFunction &VeneerFunction = CurrentIt->second;
|
||||
|
||||
MCInst &FirstInstruction = *(VeneerFunction.begin()->begin());
|
||||
const MCSymbol *VeneerTargetSymbol =
|
||||
BC.MIB->getTargetSymbol(FirstInstruction, 1);
|
||||
|
||||
// Functions can have multiple symbols
|
||||
for (StringRef Name : VeneerFunction.getNames()) {
|
||||
MCSymbol *Symbol = BC.Ctx->lookupSymbol(Name);
|
||||
VeneerDestinations[Symbol] = VeneerTargetSymbol;
|
||||
BC.SymbolToFunctionMap.erase(Symbol);
|
||||
}
|
||||
|
||||
BC.BinaryDataMap.erase(VeneerFunction.getAddress());
|
||||
BFs.erase(CurrentIt);
|
||||
}
|
||||
VeneersCount++;
|
||||
VeneerFunction.setPseudo(true);
|
||||
MCInst &FirstInstruction = *(VeneerFunction.begin()->begin());
|
||||
const MCSymbol *VeneerTargetSymbol =
|
||||
BC.MIB->getTargetSymbol(FirstInstruction, 1);
|
||||
assert(VeneerTargetSymbol && "Expecting target symbol for instruction");
|
||||
for (const MCSymbol *Symbol : VeneerFunction.getSymbols())
|
||||
VeneerDestinations[Symbol] = VeneerTargetSymbol;
|
||||
}
|
||||
|
||||
LLVM_DEBUG(dbgs() << "BOLT-INFO: number of removed linker-inserted veneers :"
|
||||
<< VeneersCount << "\n");
|
||||
outs() << "BOLT-INFO: number of removed linker-inserted veneers: "
|
||||
<< VeneersCount << "\n";
|
||||
|
||||
// Handle veneers to veneers in case they occur
|
||||
for (auto entry : VeneerDestinations) {
|
||||
const MCSymbol *src = entry.first;
|
||||
const MCSymbol *dest = entry.second;
|
||||
while (VeneerDestinations.find(dest) != VeneerDestinations.end()) {
|
||||
dest = VeneerDestinations[dest];
|
||||
}
|
||||
VeneerDestinations[src] = dest;
|
||||
for (auto &Entry : VeneerDestinations) {
|
||||
const MCSymbol *Src = Entry.first;
|
||||
const MCSymbol *Dest = Entry.second;
|
||||
while (VeneerDestinations.find(Dest) != VeneerDestinations.end())
|
||||
Dest = VeneerDestinations[Dest];
|
||||
|
||||
VeneerDestinations[Src] = Dest;
|
||||
}
|
||||
|
||||
uint64_t VeneerCallers = 0;
|
||||
|
@ -87,14 +78,16 @@ void VeneerElimination::runOnFunctions(BinaryContext &BC) {
|
|||
|
||||
VeneerCallers++;
|
||||
if (!BC.MIB->replaceBranchTarget(
|
||||
Instr, VeneerDestinations[TargetSymbol], BC.Ctx.get()))
|
||||
assert(false && "updating veneer call destination failed");
|
||||
Instr, VeneerDestinations[TargetSymbol], BC.Ctx.get())) {
|
||||
errs() << "BOLT-ERROR: updating veneer call destination failed\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLVM_DEBUG(
|
||||
dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites :"
|
||||
dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites: "
|
||||
<< VeneerCallers << "\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -313,6 +313,10 @@ void BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
|
|||
Manager.registerPass(std::make_unique<AsmDumpPass>(),
|
||||
opts::AsmDump.getNumOccurrences());
|
||||
|
||||
if (BC.isAArch64())
|
||||
Manager.registerPass(
|
||||
std::make_unique<VeneerElimination>(PrintVeneerElimination));
|
||||
|
||||
if (opts::Instrument)
|
||||
Manager.registerPass(std::make_unique<Instrumentation>(NeverPrint));
|
||||
|
||||
|
@ -339,10 +343,6 @@ void BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
|
|||
Manager.registerPass(std::make_unique<IdenticalCodeFolding>(PrintICF),
|
||||
opts::ICF);
|
||||
|
||||
if (BC.isAArch64())
|
||||
Manager.registerPass(
|
||||
std::make_unique<VeneerElimination>(PrintVeneerElimination));
|
||||
|
||||
Manager.registerPass(
|
||||
std::make_unique<SpecializeMemcpy1>(NeverPrint, opts::SpecializeMemcpy1),
|
||||
!opts::SpecializeMemcpy1.empty());
|
||||
|
|
|
@ -2891,10 +2891,9 @@ void RewriteInstance::disassembleFunctions() {
|
|||
|
||||
if (opts::PrintAll || opts::PrintDisasm)
|
||||
Function.print(outs(), "after disassembly", true);
|
||||
|
||||
BC->processInterproceduralReferences(Function);
|
||||
}
|
||||
|
||||
BC->processInterproceduralReferences();
|
||||
BC->clearJumpTableOffsets();
|
||||
BC->populateJumpTables();
|
||||
BC->skipMarkedFragments();
|
||||
|
|
|
@ -1032,17 +1032,17 @@ public:
|
|||
/// ADD x16, x16, imm
|
||||
/// BR x16
|
||||
///
|
||||
bool matchLinkerVeneer(InstructionIterator Begin, InstructionIterator End,
|
||||
uint64_t Address, const MCInst &CurInst,
|
||||
MCInst *&TargetHiBits, MCInst *&TargetLowBits,
|
||||
uint64_t &Target) const override {
|
||||
uint64_t matchLinkerVeneer(InstructionIterator Begin, InstructionIterator End,
|
||||
uint64_t Address, const MCInst &CurInst,
|
||||
MCInst *&TargetHiBits, MCInst *&TargetLowBits,
|
||||
uint64_t &Target) const override {
|
||||
if (CurInst.getOpcode() != AArch64::BR || !CurInst.getOperand(0).isReg() ||
|
||||
CurInst.getOperand(0).getReg() != AArch64::X16)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
auto I = End;
|
||||
if (I == Begin)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
--I;
|
||||
Address -= 4;
|
||||
|
@ -1051,7 +1051,7 @@ public:
|
|||
!I->getOperand(1).isReg() ||
|
||||
I->getOperand(0).getReg() != AArch64::X16 ||
|
||||
I->getOperand(1).getReg() != AArch64::X16 || !I->getOperand(2).isImm())
|
||||
return false;
|
||||
return 0;
|
||||
TargetLowBits = &*I;
|
||||
uint64_t Addr = I->getOperand(2).getImm() & 0xFFF;
|
||||
|
||||
|
@ -1060,12 +1060,12 @@ public:
|
|||
if (I->getOpcode() != AArch64::ADRP ||
|
||||
MCPlus::getNumPrimeOperands(*I) < 2 || !I->getOperand(0).isReg() ||
|
||||
!I->getOperand(1).isImm() || I->getOperand(0).getReg() != AArch64::X16)
|
||||
return false;
|
||||
return 0;
|
||||
TargetHiBits = &*I;
|
||||
Addr |= (Address + ((int64_t)I->getOperand(1).getImm() << 12)) &
|
||||
0xFFFFFFFFFFFFF000ULL;
|
||||
Target = Addr;
|
||||
return true;
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
|
||||
|
@ -1107,8 +1107,6 @@ public:
|
|||
|
||||
bool isPrefix(const MCInst &Inst) const override { return false; }
|
||||
|
||||
bool deleteREPPrefix(MCInst &Inst) const override { return false; }
|
||||
|
||||
bool createReturn(MCInst &Inst) const override {
|
||||
Inst.setOpcode(AArch64::RET);
|
||||
Inst.clear();
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// This test checks that the gold linker style veneer are properly handled
|
||||
// by BOLT.
|
||||
// Strip .rela.mytext section to simulate inserted by a linker veneers
|
||||
// that does not contain relocations.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
|
||||
# RUN: %s -o %t.o
|
||||
# RUN: %clang %cflags -fPIC -pie %t.o -o %t.exe -nostdlib \
|
||||
# RUN: -fuse-ld=lld -Wl,--no-relax -Wl,-q
|
||||
# RUN: llvm-objcopy --remove-section .rela.mytext %t.exe
|
||||
# RUN: llvm-objdump -d -j .mytext %t.exe | \
|
||||
# RUN: FileCheck --check-prefix=CHECKVENEER %s
|
||||
# RUN: llvm-bolt %t.exe -o %t.bolt --elim-link-veneers=true \
|
||||
# RUN: --lite=0 --use-old-text=0
|
||||
# RUN: llvm-objdump -d -j .text %t.bolt | FileCheck %s
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global dummy
|
||||
.type dummy, %function
|
||||
dummy:
|
||||
adrp x1, dummy
|
||||
ret
|
||||
.size dummy, .-dummy
|
||||
|
||||
.section ".mytext", "ax"
|
||||
.balign 4
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
# CHECK: <foo>:
|
||||
# CHECK-NEXT : {{.*}} bl {{.*}} <foo2>
|
||||
bl .L2
|
||||
ret
|
||||
.size foo, .-foo
|
||||
|
||||
.global foo2
|
||||
.type foo2, %function
|
||||
foo2:
|
||||
# CHECK: <foo2>:
|
||||
# CHECK-NEXT : {{.*}} bl {{.*}} <foo2>
|
||||
bl .L2
|
||||
ret
|
||||
.size foo2, .-foo2
|
||||
|
||||
.global _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
# CHECK: <_start>:
|
||||
# CHECK-NEXT: {{.*}} bl {{.*}} <foo>
|
||||
bl .L1
|
||||
adr x0, .L0
|
||||
ret
|
||||
.L0:
|
||||
.xword 0
|
||||
.size _start, .-_start
|
||||
.L1:
|
||||
# CHECKVENEER: adrp
|
||||
# CHECKVENEER-NEXT: add
|
||||
# CHECKVENEER-NEXT: br
|
||||
# CHECKVENEER-NEXT: nop
|
||||
adrp x16, foo
|
||||
add x16, x16, #:lo12:foo
|
||||
br x16
|
||||
nop
|
||||
.L2:
|
||||
# CHECKVENEER-NEXT: adrp
|
||||
# CHECKVENEER-NEXT: add
|
||||
# CHECKVENEER-NEXT: br
|
||||
# CHECKVENEER-NEXT: nop
|
||||
adrp x16, foo2
|
||||
add x16, x16, #:lo12:foo2
|
||||
br x16
|
||||
nop
|
|
@ -0,0 +1,46 @@
|
|||
// This test checks that the veneer are properly handled by BOLT.
|
||||
// Strip .rela.mytext section to simulate inserted by a linker veneers
|
||||
// that does not contain relocations.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
|
||||
# RUN: %s -o %t.o
|
||||
# RUN: %clang %cflags -fPIC -pie %t.o -o %t.exe -nostdlib \
|
||||
# RUN: -fuse-ld=lld -Wl,--no-relax -Wl,-q
|
||||
# RUN: llvm-objdump -d --disassemble-symbols='myveneer' %t.exe | \
|
||||
# RUN: FileCheck --check-prefix=CHECKVENEER %s
|
||||
# RUN: llvm-objcopy --remove-section .rela.mytext %t.exe
|
||||
# RUN: llvm-bolt %t.exe -o %t.bolt --elim-link-veneers=true --lite=0
|
||||
# RUN: llvm-objdump -d -j .text --disassemble-symbols='myveneer' %t.bolt | \
|
||||
# RUN: FileCheck --check-prefix=CHECKOUTVENEER %s
|
||||
# RUN: llvm-objdump -d --disassemble-symbols='_start' %t.bolt | FileCheck %s
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
adrp x1, foo
|
||||
ret
|
||||
.size foo, .-foo
|
||||
|
||||
.section ".mytext", "ax"
|
||||
.balign 4
|
||||
# CHECKOUTVENEER-NOT: {{.*}} <myveneer>:
|
||||
.global myveneer
|
||||
.type myveneer, %function
|
||||
myveneer:
|
||||
# CHECKVENEER: adrp
|
||||
# CHECKVENEER-NEXT: add
|
||||
adrp x16, foo
|
||||
add x16, x16, #:lo12:foo
|
||||
br x16
|
||||
nop
|
||||
.size myveneer, .-myveneer
|
||||
|
||||
.global _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
# CHECK: {{.*}} bl {{.*}} <foo>
|
||||
bl myveneer
|
||||
ret
|
||||
.size _start, .-_start
|
Loading…
Reference in New Issue