1 | //===- bolt/Passes/PLTCall.h - PLT call optimization ----------------------===// |
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 file implements the PLTCall class, which replaces calls to PLT entries |
10 | // with indirect calls against GOT. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "bolt/Passes/PLTCall.h" |
15 | #include "llvm/Support/CommandLine.h" |
16 | |
17 | #define DEBUG_TYPE "bolt-plt" |
18 | |
19 | using namespace llvm; |
20 | |
21 | namespace opts { |
22 | |
23 | extern cl::OptionCategory BoltOptCategory; |
24 | |
25 | static cl::opt<bolt::PLTCall::OptType> |
26 | PLT("plt" , cl::desc("optimize PLT calls (requires linking with -znow)" ), |
27 | cl::init(Val: bolt::PLTCall::OT_NONE), |
28 | cl::values(clEnumValN(bolt::PLTCall::OT_NONE, "none" , |
29 | "do not optimize PLT calls" ), |
30 | clEnumValN(bolt::PLTCall::OT_HOT, "hot" , |
31 | "optimize executed (hot) PLT calls" ), |
32 | clEnumValN(bolt::PLTCall::OT_ALL, "all" , |
33 | "optimize all PLT calls" )), |
34 | cl::ZeroOrMore, cl::cat(BoltOptCategory)); |
35 | } |
36 | |
37 | namespace llvm { |
38 | namespace bolt { |
39 | |
40 | Error PLTCall::runOnFunctions(BinaryContext &BC) { |
41 | if (opts::PLT == OT_NONE) |
42 | return Error::success(); |
43 | |
44 | uint64_t NumCallsOptimized = 0; |
45 | for (auto &BFI : BC.getBinaryFunctions()) { |
46 | BinaryFunction &Function = BFI.second; |
47 | if (!shouldOptimize(BF: Function)) |
48 | continue; |
49 | |
50 | if (opts::PLT == OT_HOT && |
51 | Function.getExecutionCount() == BinaryFunction::COUNT_NO_PROFILE) |
52 | continue; |
53 | |
54 | for (BinaryBasicBlock &BB : Function) { |
55 | if (opts::PLT == OT_HOT && !BB.getKnownExecutionCount()) |
56 | continue; |
57 | |
58 | for (auto II = BB.begin(); II != BB.end(); II++) { |
59 | if (!BC.MIB->isCall(Inst: *II)) |
60 | continue; |
61 | const MCSymbol *CallSymbol = BC.MIB->getTargetSymbol(Inst: *II); |
62 | if (!CallSymbol) |
63 | continue; |
64 | const BinaryFunction *CalleeBF = BC.getFunctionForSymbol(Symbol: CallSymbol); |
65 | if (!CalleeBF || !CalleeBF->isPLTFunction()) |
66 | continue; |
67 | const InstructionListType NewCode = BC.MIB->createIndirectPLTCall( |
68 | DirectCall: std::move(*II), TargetLocation: CalleeBF->getPLTSymbol(), Ctx: BC.Ctx.get()); |
69 | II = BB.replaceInstruction(II, Replacement: NewCode); |
70 | assert(!NewCode.empty() && "PLT Call replacement must be non-empty" ); |
71 | std::advance(i&: II, n: NewCode.size() - 1); |
72 | BC.MIB->addAnnotation(Inst&: *II, Name: "PLTCall" , Val: true); |
73 | ++NumCallsOptimized; |
74 | } |
75 | } |
76 | } |
77 | |
78 | if (NumCallsOptimized) { |
79 | BC.RequiresZNow = true; |
80 | BC.outs() << "BOLT-INFO: " << NumCallsOptimized |
81 | << " PLT calls in the binary were optimized.\n" ; |
82 | } |
83 | return Error::success(); |
84 | } |
85 | |
86 | } // namespace bolt |
87 | } // namespace llvm |
88 | |