| 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 | |