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
17using namespace llvm;
18
19namespace opts {
20
21extern cl::OptionCategory BoltOptCategory;
22
23static llvm::cl::opt<bool>
24 EliminateVeneers("elim-link-veneers",
25 cl::desc("run veneer elimination pass"), cl::init(Val: true),
26 cl::Hidden, cl::cat(BoltOptCategory));
27} // namespace opts
28
29namespace llvm {
30namespace bolt {
31
32Error VeneerElimination::runOnFunctions(BinaryContext &BC) {
33 if (!opts::EliminateVeneers || !BC.isAArch64())
34 return Error::success();
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(Inst: FirstInstruction, OpNum: 1);
49 assert(VeneerTargetSymbol && "Expecting target symbol for instruction");
50 for (const MCSymbol *Symbol : VeneerFunction.getSymbols())
51 VeneerDestinations[Symbol] = VeneerTargetSymbol;
52 }
53
54 BC.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(x: 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(Inst: Instr) || BC.MIB->isIndirectCall(Inst: Instr))
73 continue;
74
75 const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst: Instr, OpNum: 0);
76 if (VeneerDestinations.find(x: TargetSymbol) == VeneerDestinations.end())
77 continue;
78
79 VeneerCallers++;
80 if (!BC.MIB->replaceBranchTarget(
81 Inst&: Instr, TBB: VeneerDestinations[TargetSymbol], Ctx: BC.Ctx.get())) {
82 return createFatalBOLTError(
83 S: "BOLT-ERROR: updating veneer call destination failed\n");
84 }
85 }
86 }
87 }
88
89 LLVM_DEBUG(
90 dbgs() << "BOLT-INFO: number of linker-inserted veneers call sites: "
91 << VeneerCallers << "\n");
92 (void)VeneerCallers;
93 return Error::success();
94}
95
96} // namespace bolt
97} // namespace llvm
98

source code of bolt/lib/Passes/VeneerElimination.cpp