1 //===- bolt/Passes/VeneerElimination.cpp ----------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This class implements a pass that removes linker-inserted veneers from the 10 // code and redirects veneer callers to call to veneers destinations 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "bolt/Passes/VeneerElimination.h" 15 #define DEBUG_TYPE "veneer-elim" 16 17 using namespace llvm; 18 19 namespace opts { 20 21 extern cl::OptionCategory BoltOptCategory; 22 23 static llvm::cl::opt<bool> 24 EliminateVeneers("elim-link-veneers", 25 cl::desc("run veneer elimination pass"), cl::init(true), 26 cl::Hidden, cl::cat(BoltOptCategory)); 27 } // namespace opts 28 29 namespace llvm { 30 namespace bolt { 31 32 static bool isPossibleVeneer(const BinaryFunction &BF) { 33 return BF.isAArch64Veneer() || BF.getOneName().starts_with("__AArch64"); 34 } 35 36 Error VeneerElimination::runOnFunctions(BinaryContext &BC) { 37 if (!opts::EliminateVeneers || !BC.isAArch64()) 38 return Error::success(); 39 40 std::unordered_map<const MCSymbol *, const MCSymbol *> VeneerDestinations; 41 uint64_t NumEliminatedVeneers = 0; 42 for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 43 if (!isPossibleVeneer(BF)) 44 continue; 45 46 if (BF.isIgnored()) 47 continue; 48 49 MCInst &FirstInstruction = *(BF.begin()->begin()); 50 const MCSymbol *VeneerTargetSymbol = 0; 51 uint64_t TargetAddress; 52 if (BC.MIB->isTailCall(FirstInstruction)) { 53 VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction); 54 } else if (BC.MIB->matchAbsLongVeneer(BF, TargetAddress)) { 55 if (BinaryFunction *TargetBF = 56 BC.getBinaryFunctionAtAddress(TargetAddress)) 57 VeneerTargetSymbol = TargetBF->getSymbol(); 58 } else if (BC.MIB->hasAnnotation(FirstInstruction, "AArch64Veneer")) { 59 VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction, 1); 60 } 61 62 if (!VeneerTargetSymbol) 63 continue; 64 65 for (const MCSymbol *Symbol : BF.getSymbols()) 66 VeneerDestinations[Symbol] = VeneerTargetSymbol; 67 68 NumEliminatedVeneers++; 69 BF.setPseudo(true); 70 } 71 72 BC.outs() << "BOLT-INFO: number of removed linker-inserted veneers: " 73 << NumEliminatedVeneers << '\n'; 74 75 // Handle veneers to veneers in case they occur 76 for (auto &Entry : VeneerDestinations) { 77 const MCSymbol *Src = Entry.first; 78 const MCSymbol *Dest = Entry.second; 79 while (VeneerDestinations.find(Dest) != VeneerDestinations.end()) 80 Dest = VeneerDestinations[Dest]; 81 82 VeneerDestinations[Src] = Dest; 83 } 84 85 uint64_t VeneerCallers = 0; 86 for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 87 for (BinaryBasicBlock &BB : BF) { 88 for (MCInst &Instr : BB) { 89 if (!BC.MIB->isCall(Instr) || BC.MIB->isIndirectCall(Instr)) 90 continue; 91 92 const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Instr, 0); 93 auto It = VeneerDestinations.find(TargetSymbol); 94 if (It == VeneerDestinations.end()) 95 continue; 96 97 VeneerCallers++; 98 BC.MIB->replaceBranchTarget(Instr, It->second, BC.Ctx.get()); 99 } 100 } 101 } 102 103 LLVM_DEBUG( 104 dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites: " 105 << VeneerCallers << "\n"); 106 (void)VeneerCallers; 107 return Error::success(); 108 } 109 110 } // namespace bolt 111 } // namespace llvm 112