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