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 the
10// original function entry points. This ensures that only the new/optimized code
11// executes and that the old code is never used. This is necessary due to
12// current BOLT limitations of not being able to duplicate all function's
13// associated metadata (e.g., .eh_frame, exception ranges, debug info,
14// jump-tables).
15//
16// NOTE: A successful run of 'scanExternalRefs' can relax this requirement as
17// it also ensures that old code is never executed.
18//
19//===----------------------------------------------------------------------===//
20
21#include "bolt/Passes/PatchEntries.h"
22#include "bolt/Utils/CommandLineOpts.h"
23#include "bolt/Utils/NameResolver.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/Support/CommandLine.h"
26
27namespace opts {
28extern llvm::cl::OptionCategory BoltCategory;
29extern llvm::cl::opt<unsigned> Verbosity;
30} // namespace opts
31
32namespace llvm {
33namespace bolt {
34
35Error PatchEntries::runOnFunctions(BinaryContext &BC) {
36 if (!opts::ForcePatch) {
37 // Mark the binary for patching if we did not create external references
38 // for original code in any of functions we are not going to emit.
39 bool NeedsPatching = llvm::any_of(
40 Range: llvm::make_second_range(c&: BC.getBinaryFunctions()),
41 P: [&](BinaryFunction &BF) {
42 return (!BC.shouldEmit(Function: BF) && !BF.hasExternalRefRelocations()) ||
43 BF.needsPatch();
44 });
45
46 if (!NeedsPatching)
47 return Error::success();
48 }
49
50 if (opts::Verbosity >= 1)
51 BC.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, Target: BC.Ctx->createTempSymbol(), Ctx: BC.Ctx.get());
58 PatchSize = BC.computeCodeSize(Beg: Seq.begin(), End: 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.needsPatch() && 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(Callback: [&](uint64_t Offset,
80 const MCSymbol *Symbol) {
81 if (Offset < NextValidByte) {
82 if (opts::Verbosity >= 1)
83 BC.outs() << "BOLT-INFO: unable to patch entry point in " << Function
84 << " at offset 0x" << Twine::utohexstr(Val: Offset) << '\n';
85 return false;
86 }
87
88 PendingPatches.emplace_back(
89 args: Patch{.Symbol: Symbol, .Address: Function.getAddress() + Offset});
90 NextValidByte = Offset + PatchSize;
91 if (NextValidByte > Function.getMaxSize()) {
92 if (opts::Verbosity >= 1)
93 BC.outs() << "BOLT-INFO: function " << Function
94 << " too small to patch its entry point\n";
95 return false;
96 }
97
98 return true;
99 });
100
101 if (!Success) {
102 // If the original function entries cannot be patched, then we cannot
103 // safely emit new function body.
104 BC.errs() << "BOLT-WARNING: failed to patch entries in " << Function
105 << ". The function will not be optimized\n";
106 Function.setIgnored();
107 continue;
108 }
109
110 for (Patch &Patch : PendingPatches) {
111 // Add instruction patch to the binary.
112 InstructionListType Instructions;
113 BC.MIB->createLongTailCall(Seq&: Instructions, Target: Patch.Symbol, Ctx: BC.Ctx.get());
114 BinaryFunction *PatchFunction = BC.createInstructionPatch(
115 Address: Patch.Address, Instructions,
116 Name: NameResolver::append(UniqueName: Patch.Symbol->getName(), Suffix: ".org.0"));
117
118 // Verify the size requirements.
119 uint64_t HotSize, ColdSize;
120 std::tie(args&: HotSize, args&: ColdSize) = BC.calculateEmittedSize(BF&: *PatchFunction);
121 assert(!ColdSize && "unexpected cold code");
122 assert(HotSize <= PatchSize && "max patch size exceeded");
123 }
124 }
125 return Error::success();
126}
127
128} // end namespace bolt
129} // end namespace llvm
130

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of bolt/lib/Passes/PatchEntries.cpp