//===- bolt/Passes/VeneerElimination.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This class implements a pass that removes linker-inserted veneers from the // code and redirects veneer callers to call to veneers destinations // //===----------------------------------------------------------------------===// #include "bolt/Passes/VeneerElimination.h" #define DEBUG_TYPE "veneer-elim" using namespace llvm; namespace opts { extern cl::OptionCategory BoltOptCategory; static llvm::cl::opt EliminateVeneers("elim-link-veneers", cl::desc("run veneer elimination pass"), cl::init(true), cl::Hidden, cl::cat(BoltOptCategory)); } // namespace opts namespace llvm { namespace bolt { static bool isPossibleVeneer(const BinaryFunction &BF) { return BF.isAArch64Veneer() || BF.getOneName().starts_with("__AArch64"); } Error VeneerElimination::runOnFunctions(BinaryContext &BC) { if (!opts::EliminateVeneers || !BC.isAArch64()) return Error::success(); std::unordered_map VeneerDestinations; uint64_t NumEliminatedVeneers = 0; for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { if (!isPossibleVeneer(BF)) continue; if (BF.isIgnored()) continue; MCInst &FirstInstruction = *(BF.begin()->begin()); const MCSymbol *VeneerTargetSymbol = 0; uint64_t TargetAddress; if (BC.MIB->isTailCall(FirstInstruction)) { VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction); } else if (BC.MIB->matchAbsLongVeneer(BF, TargetAddress)) { if (BinaryFunction *TargetBF = BC.getBinaryFunctionAtAddress(TargetAddress)) VeneerTargetSymbol = TargetBF->getSymbol(); } else if (BC.MIB->hasAnnotation(FirstInstruction, "AArch64Veneer")) { VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction, 1); } if (!VeneerTargetSymbol) continue; for (const MCSymbol *Symbol : BF.getSymbols()) VeneerDestinations[Symbol] = VeneerTargetSymbol; NumEliminatedVeneers++; BF.setPseudo(true); } BC.outs() << "BOLT-INFO: number of removed linker-inserted veneers: " << NumEliminatedVeneers << '\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; } uint64_t VeneerCallers = 0; for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { for (BinaryBasicBlock &BB : BF) { for (MCInst &Instr : BB) { if (!BC.MIB->isCall(Instr) || BC.MIB->isIndirectCall(Instr)) continue; const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Instr, 0); auto It = VeneerDestinations.find(TargetSymbol); if (It == VeneerDestinations.end()) continue; VeneerCallers++; BC.MIB->replaceBranchTarget(Instr, It->second, BC.Ctx.get()); } } } LLVM_DEBUG( dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites: " << VeneerCallers << "\n"); (void)VeneerCallers; return Error::success(); } } // namespace bolt } // namespace llvm