brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.7 KiB · 55f7513 Raw
130 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the PatchEntries class that is used for patching the10// original function entry points. This ensures that only the new/optimized code11// executes and that the old code is never used. This is necessary due to12// current BOLT limitations of not being able to duplicate all function's13// 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 as17// 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 opts31 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 references38    // for original code in any of functions we are not going to emit.39    bool NeedsPatching = llvm::any_of(40        llvm::make_second_range(BC.getBinaryFunctions()),41        [&](BinaryFunction &BF) {42          return (!BC.shouldEmit(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, 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.needsPatch() && Function.getSize() < PatchThreshold)71      continue;72 73    // List of patches for function entries. We either successfully patch74    // all entries or, if we cannot patch one or more, do no patch any and75    // mark the function as ignorable.76    std::vector<Patch> PendingPatches;77 78    uint64_t NextValidByte = 0; // offset of the byte past the last patch79    bool Success = Function.forEachEntryPoint([&](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 " << Function84                    << " at offset 0x" << Twine::utohexstr(Offset) << '\n';85        return false;86      }87 88      PendingPatches.emplace_back(89          Patch{Symbol, Function.getAddress() + Offset});90      NextValidByte = Offset + PatchSize;91      if (NextValidByte > Function.getMaxSize()) {92        if (opts::Verbosity >= 1)93          BC.outs() << "BOLT-INFO: function " << Function94                    << " 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 cannot103      // safely emit new function body.104      BC.errs() << "BOLT-WARNING: failed to patch entries in " << Function105                << ". 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(Instructions, Patch.Symbol, BC.Ctx.get());114      BinaryFunction *PatchFunction = BC.createInstructionPatch(115          Patch.Address, Instructions,116          NameResolver::append(Patch.Symbol->getName(), ".org.0"));117 118      // Verify the size requirements.119      uint64_t HotSize, ColdSize;120      std::tie(HotSize, ColdSize) = BC.calculateEmittedSize(*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 bolt129} // end namespace llvm130