1 //===- bolt/Passes/PatchEntries.cpp - Pass for patching function entries --===//
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 PatchEntries class that is used for patching
10 // the original function entry points.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "bolt/Passes/PatchEntries.h"
15 #include "bolt/Utils/NameResolver.h"
16 #include "llvm/Support/CommandLine.h"
17
18 namespace opts {
19
20 extern llvm::cl::OptionCategory BoltCategory;
21
22 extern llvm::cl::opt<unsigned> Verbosity;
23
24 llvm::cl::opt<bool>
25 ForcePatch("force-patch",
26 llvm::cl::desc("force patching of original entry points"),
27 llvm::cl::Hidden, llvm::cl::cat(BoltCategory));
28 }
29
30 namespace llvm {
31 namespace bolt {
32
runOnFunctions(BinaryContext & BC)33 void PatchEntries::runOnFunctions(BinaryContext &BC) {
34 if (!opts::ForcePatch) {
35 // Mark the binary for patching if we did not create external references
36 // for original code in any of functions we are not going to emit.
37 bool NeedsPatching = false;
38 for (auto &BFI : BC.getBinaryFunctions()) {
39 BinaryFunction &Function = BFI.second;
40 if (!BC.shouldEmit(Function) && !Function.hasExternalRefRelocations()) {
41 NeedsPatching = true;
42 break;
43 }
44 }
45
46 if (!NeedsPatching)
47 return;
48 }
49
50 if (opts::Verbosity >= 1)
51 outs() << "BOLT-INFO: patching entries in original code\n";
52
53 // Calculate the size of the patch.
54 static size_t PatchSize = 0;
55 if (!PatchSize) {
56 InstructionListType Seq;
57 BC.MIB->createLongTailCall(Seq, BC.Ctx->createTempSymbol(), BC.Ctx.get());
58 PatchSize = BC.computeCodeSize(Seq.begin(), Seq.end());
59 }
60
61 for (auto &BFI : BC.getBinaryFunctions()) {
62 BinaryFunction &Function = BFI.second;
63
64 // Patch original code only for functions that will be emitted.
65 if (!BC.shouldEmit(Function))
66 continue;
67
68 // Check if we can skip patching the function.
69 if (!opts::ForcePatch && !Function.hasEHRanges() &&
70 Function.getSize() < PatchThreshold)
71 continue;
72
73 // List of patches for function entries. We either successfully patch
74 // all entries or, if we cannot patch one or more, do no patch any and
75 // mark the function as ignorable.
76 std::vector<Patch> PendingPatches;
77
78 uint64_t NextValidByte = 0; // offset of the byte past the last patch
79 bool Success = Function.forEachEntryPoint([&](uint64_t Offset,
80 const MCSymbol *Symbol) {
81 if (Offset < NextValidByte) {
82 if (opts::Verbosity >= 1)
83 outs() << "BOLT-INFO: unable to patch entry point in " << Function
84 << " at offset 0x" << Twine::utohexstr(Offset) << '\n';
85 return false;
86 }
87
88 PendingPatches.emplace_back(Patch{Symbol, Function.getAddress() + Offset,
89 Function.getFileOffset() + Offset,
90 Function.getOriginSection()});
91 NextValidByte = Offset + PatchSize;
92 if (NextValidByte > Function.getMaxSize()) {
93 if (opts::Verbosity >= 1)
94 outs() << "BOLT-INFO: function " << Function
95 << " too small to patch its entry point\n";
96 return false;
97 }
98
99 return true;
100 });
101
102 if (!Success) {
103 // If the original function entries cannot be patched, then we cannot
104 // safely emit new function body.
105 errs() << "BOLT-WARNING: failed to patch entries in " << Function
106 << ". The function will not be optimized.\n";
107 Function.setIgnored();
108 continue;
109 }
110
111 for (Patch &Patch : PendingPatches) {
112 BinaryFunction *PatchFunction = BC.createInjectedBinaryFunction(
113 NameResolver::append(Patch.Symbol->getName(), ".org.0"));
114 // Force the function to be emitted at the given address.
115 PatchFunction->setOutputAddress(Patch.Address);
116 PatchFunction->setFileOffset(Patch.FileOffset);
117 PatchFunction->setOriginSection(Patch.Section);
118
119 InstructionListType Seq;
120 BC.MIB->createLongTailCall(Seq, Patch.Symbol, BC.Ctx.get());
121 PatchFunction->addBasicBlock()->addInstructions(Seq);
122
123 // Verify the size requirements.
124 uint64_t HotSize, ColdSize;
125 std::tie(HotSize, ColdSize) = BC.calculateEmittedSize(*PatchFunction);
126 assert(!ColdSize && "unexpected cold code");
127 assert(HotSize <= PatchSize && "max patch size exceeded");
128 }
129
130 Function.setIsPatched(true);
131 }
132 }
133
134 } // end namespace bolt
135 } // end namespace llvm
136