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