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   std::map<uint64_t, BinaryFunction> &BFs = BC.getBinaryFunctions();
37   std::unordered_map<const MCSymbol *, const MCSymbol *> VeneerDestinations;
38   uint64_t VeneersCount = 0;
39   for (auto &It : BFs) {
40     BinaryFunction &VeneerFunction = It.second;
41     if (!VeneerFunction.isAArch64Veneer())
42       continue;
43 
44     VeneersCount++;
45     VeneerFunction.setPseudo(true);
46     MCInst &FirstInstruction = *(VeneerFunction.begin()->begin());
47     const MCSymbol *VeneerTargetSymbol =
48         BC.MIB->getTargetSymbol(FirstInstruction, 1);
49     assert(VeneerTargetSymbol && "Expecting target symbol for instruction");
50     for (const MCSymbol *Symbol : VeneerFunction.getSymbols())
51       VeneerDestinations[Symbol] = VeneerTargetSymbol;
52   }
53 
54   outs() << "BOLT-INFO: number of removed linker-inserted veneers: "
55          << VeneersCount << "\n";
56 
57   // Handle veneers to veneers in case they occur
58   for (auto &Entry : VeneerDestinations) {
59     const MCSymbol *Src = Entry.first;
60     const MCSymbol *Dest = Entry.second;
61     while (VeneerDestinations.find(Dest) != VeneerDestinations.end())
62       Dest = VeneerDestinations[Dest];
63 
64     VeneerDestinations[Src] = Dest;
65   }
66 
67   uint64_t VeneerCallers = 0;
68   for (auto &It : BFs) {
69     BinaryFunction &Function = It.second;
70     for (BinaryBasicBlock &BB : Function) {
71       for (MCInst &Instr : BB) {
72         if (!BC.MIB->isCall(Instr) || BC.MIB->isIndirectCall(Instr))
73           continue;
74 
75         const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Instr, 0);
76         if (VeneerDestinations.find(TargetSymbol) == VeneerDestinations.end())
77           continue;
78 
79         VeneerCallers++;
80         if (!BC.MIB->replaceBranchTarget(
81                 Instr, VeneerDestinations[TargetSymbol], BC.Ctx.get())) {
82           errs() << "BOLT-ERROR: updating veneer call destination failed\n";
83           exit(1);
84         }
85       }
86     }
87   }
88 
89   LLVM_DEBUG(
90       dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites: "
91              << VeneerCallers << "\n");
92 }
93 
94 } // namespace bolt
95 } // namespace llvm
96