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