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