#include "bolt/Passes/PatchEntries.h"
#include "bolt/Utils/NameResolver.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
namespace opts {
extern llvm::cl::OptionCategory BoltCategory;
extern llvm::cl::opt<unsigned> Verbosity;
llvm::cl::opt<bool>
ForcePatch("force-patch",
llvm::cl::desc("force patching of original entry points"),
llvm::cl::Hidden, llvm::cl::cat(BoltCategory));
}
namespace llvm {
namespace bolt {
Error PatchEntries::runOnFunctions(BinaryContext &BC) {
if (!opts::ForcePatch) {
bool NeedsPatching = llvm::any_of(
llvm::make_second_range(BC.getBinaryFunctions()),
[&](BinaryFunction &BF) {
return !BC.shouldEmit(BF) && !BF.hasExternalRefRelocations();
});
if (!NeedsPatching)
return Error::success();
}
if (opts::Verbosity >= 1)
BC.outs() << "BOLT-INFO: patching entries in original code\n";
static size_t PatchSize = 0;
if (!PatchSize) {
InstructionListType Seq;
BC.MIB->createLongTailCall(Seq, BC.Ctx->createTempSymbol(), BC.Ctx.get());
PatchSize = BC.computeCodeSize(Seq.begin(), Seq.end());
}
for (auto &BFI : BC.getBinaryFunctions()) {
BinaryFunction &Function = BFI.second;
if (!BC.shouldEmit(Function))
continue;
if (!opts::ForcePatch && !Function.hasEHRanges() &&
Function.getSize() < PatchThreshold)
continue;
std::vector<Patch> PendingPatches;
uint64_t NextValidByte = 0;
bool Success = Function.forEachEntryPoint([&](uint64_t Offset,
const MCSymbol *Symbol) {
if (Offset < NextValidByte) {
if (opts::Verbosity >= 1)
BC.outs() << "BOLT-INFO: unable to patch entry point in " << Function
<< " at offset 0x" << Twine::utohexstr(Offset) << '\n';
return false;
}
PendingPatches.emplace_back(Patch{Symbol, Function.getAddress() + Offset,
Function.getFileOffset() + Offset,
Function.getOriginSection()});
NextValidByte = Offset + PatchSize;
if (NextValidByte > Function.getMaxSize()) {
if (opts::Verbosity >= 1)
BC.outs() << "BOLT-INFO: function " << Function
<< " too small to patch its entry point\n";
return false;
}
return true;
});
if (!Success) {
if (BC.isAArch64()) {
if (opts::ForcePatch) {
BC.errs() << "BOLT-ERROR: unable to patch entries in " << Function
<< "\n";
return createFatalBOLTError("");
}
continue;
}
BC.errs() << "BOLT-WARNING: failed to patch entries in " << Function
<< ". The function will not be optimized.\n";
Function.setIgnored();
continue;
}
for (Patch &Patch : PendingPatches) {
BinaryFunction *PatchFunction = BC.createInjectedBinaryFunction(
NameResolver::append(Patch.Symbol->getName(), ".org.0"));
PatchFunction->setOutputAddress(Patch.Address);
PatchFunction->setFileOffset(Patch.FileOffset);
PatchFunction->setOriginSection(Patch.Section);
InstructionListType Seq;
BC.MIB->createLongTailCall(Seq, Patch.Symbol, BC.Ctx.get());
PatchFunction->addBasicBlock()->addInstructions(Seq);
uint64_t HotSize, ColdSize;
std::tie(HotSize, ColdSize) = BC.calculateEmittedSize(*PatchFunction);
assert(!ColdSize && "unexpected cold code");
assert(HotSize <= PatchSize && "max patch size exceeded");
}
Function.setIsPatched(true);
}
return Error::success();
}
}
}