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"), 26 cl::init(true), 27 cl::ZeroOrMore, 28 cl::Hidden, 29 cl::cat(BoltOptCategory)); 30 } // namespace opts 31 32 namespace llvm { 33 namespace bolt { 34 35 void VeneerElimination::runOnFunctions(BinaryContext &BC) { 36 if (!opts::EliminateVeneers || !BC.isAArch64()) 37 return; 38 39 auto &BFs = BC.getBinaryFunctions(); 40 std::unordered_map<const MCSymbol *, const MCSymbol *> VeneerDestinations; 41 uint64_t VeneersCount = 0; 42 for (auto It = BFs.begin(); It != BFs.end();) { 43 auto CurrentIt = It; 44 ++It; 45 46 if (CurrentIt->second.isAArch64Veneer()) { 47 VeneersCount++; 48 BinaryFunction &VeneerFunction = CurrentIt->second; 49 50 MCInst &FirstInstruction = *(VeneerFunction.begin()->begin()); 51 const MCSymbol *VeneerTargetSymbol = 52 BC.MIB->getTargetSymbol(FirstInstruction, 1); 53 54 // Functions can have multiple symbols 55 for (StringRef Name : VeneerFunction.getNames()) { 56 MCSymbol *Symbol = BC.Ctx->lookupSymbol(Name); 57 VeneerDestinations[Symbol] = VeneerTargetSymbol; 58 BC.SymbolToFunctionMap.erase(Symbol); 59 } 60 61 BC.BinaryDataMap.erase(VeneerFunction.getAddress()); 62 BFs.erase(CurrentIt); 63 } 64 } 65 66 LLVM_DEBUG(dbgs() << "BOLT-INFO: number of removed linker-inserted veneers :" 67 << VeneersCount << "\n"); 68 69 // Handle veneers to veneers in case they occur 70 for (auto entry : VeneerDestinations) { 71 const MCSymbol *src = entry.first; 72 const MCSymbol *dest = entry.second; 73 while (VeneerDestinations.find(dest) != VeneerDestinations.end()) { 74 dest = VeneerDestinations[dest]; 75 } 76 VeneerDestinations[src] = dest; 77 } 78 79 uint64_t VeneerCallers = 0; 80 for (auto &It : BFs) { 81 BinaryFunction &Function = It.second; 82 for (BinaryBasicBlock &BB : Function) { 83 for (MCInst &Instr : BB) { 84 if (!BC.MIB->isCall(Instr) || BC.MIB->isIndirectCall(Instr)) 85 continue; 86 87 const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Instr, 0); 88 if (VeneerDestinations.find(TargetSymbol) == VeneerDestinations.end()) 89 continue; 90 91 VeneerCallers++; 92 if (!BC.MIB->replaceBranchTarget( 93 Instr, VeneerDestinations[TargetSymbol], BC.Ctx.get())) 94 assert(false && "updating veneer call destination failed"); 95 } 96 } 97 } 98 99 LLVM_DEBUG( 100 dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites :" 101 << VeneerCallers << "\n"); 102 } 103 104 } // namespace bolt 105 } // namespace llvm 106