1*a34c753fSRafael Auler //===------HugifyRuntimeLibrary.cpp - The Hugify Runtime Library ----------===// 2*a34c753fSRafael Auler // 3*a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5*a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*a34c753fSRafael Auler // 7*a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8*a34c753fSRafael Auler 9*a34c753fSRafael Auler #include "bolt/RuntimeLibs/HugifyRuntimeLibrary.h" 10*a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 11*a34c753fSRafael Auler #include "llvm/ExecutionEngine/RuntimeDyld.h" 12*a34c753fSRafael Auler #include "llvm/MC/MCStreamer.h" 13*a34c753fSRafael Auler #include "llvm/Support/Alignment.h" 14*a34c753fSRafael Auler #include "llvm/Support/CommandLine.h" 15*a34c753fSRafael Auler 16*a34c753fSRafael Auler using namespace llvm; 17*a34c753fSRafael Auler using namespace bolt; 18*a34c753fSRafael Auler 19*a34c753fSRafael Auler namespace opts { 20*a34c753fSRafael Auler 21*a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory; 22*a34c753fSRafael Auler 23*a34c753fSRafael Auler extern cl::opt<bool> HotText; 24*a34c753fSRafael Auler 25*a34c753fSRafael Auler cl::opt<bool> 26*a34c753fSRafael Auler Hugify("hugify", 27*a34c753fSRafael Auler cl::desc("Automatically put hot code on 2MB page(s) (hugify) at " 28*a34c753fSRafael Auler "runtime. No manual call to hugify is needed in the binary " 29*a34c753fSRafael Auler "(which is what --hot-text relies on)."), 30*a34c753fSRafael Auler cl::ZeroOrMore, cl::cat(BoltOptCategory)); 31*a34c753fSRafael Auler 32*a34c753fSRafael Auler static cl::opt<std::string> RuntimeHugifyLib( 33*a34c753fSRafael Auler "runtime-hugify-lib", 34*a34c753fSRafael Auler cl::desc("specify file name of the runtime hugify library"), cl::ZeroOrMore, 35*a34c753fSRafael Auler cl::init("libbolt_rt_hugify.a"), cl::cat(BoltOptCategory)); 36*a34c753fSRafael Auler 37*a34c753fSRafael Auler } // namespace opts 38*a34c753fSRafael Auler 39*a34c753fSRafael Auler void HugifyRuntimeLibrary::adjustCommandLineOptions( 40*a34c753fSRafael Auler const BinaryContext &BC) const { 41*a34c753fSRafael Auler if (opts::HotText) { 42*a34c753fSRafael Auler errs() 43*a34c753fSRafael Auler << "BOLT-ERROR: -hot-text should be applied to binaries with " 44*a34c753fSRafael Auler "pre-compiled manual hugify support, while -hugify will add hugify " 45*a34c753fSRafael Auler "support automatcally. These two options cannot both be present.\n"; 46*a34c753fSRafael Auler exit(1); 47*a34c753fSRafael Auler } 48*a34c753fSRafael Auler // After the check, we set HotText to be true because automated hugify support 49*a34c753fSRafael Auler // relies on it. 50*a34c753fSRafael Auler opts::HotText = true; 51*a34c753fSRafael Auler if (!BC.StartFunctionAddress) { 52*a34c753fSRafael Auler errs() << "BOLT-ERROR: hugify runtime libraries require a known entry " 53*a34c753fSRafael Auler "point of " 54*a34c753fSRafael Auler "the input binary\n"; 55*a34c753fSRafael Auler exit(1); 56*a34c753fSRafael Auler } 57*a34c753fSRafael Auler } 58*a34c753fSRafael Auler 59*a34c753fSRafael Auler void HugifyRuntimeLibrary::emitBinary(BinaryContext &BC, MCStreamer &Streamer) { 60*a34c753fSRafael Auler const BinaryFunction *StartFunction = 61*a34c753fSRafael Auler BC.getBinaryFunctionAtAddress(*(BC.StartFunctionAddress)); 62*a34c753fSRafael Auler assert(!StartFunction->isFragment() && "expected main function fragment"); 63*a34c753fSRafael Auler if (!StartFunction) { 64*a34c753fSRafael Auler errs() << "BOLT-ERROR: failed to locate function at binary start address\n"; 65*a34c753fSRafael Auler exit(1); 66*a34c753fSRafael Auler } 67*a34c753fSRafael Auler 68*a34c753fSRafael Auler const auto Flags = BinarySection::getFlags(/*IsReadOnly=*/false, 69*a34c753fSRafael Auler /*IsText=*/false, 70*a34c753fSRafael Auler /*IsAllocatable=*/true); 71*a34c753fSRafael Auler MCSectionELF *Section = 72*a34c753fSRafael Auler BC.Ctx->getELFSection(".bolt.hugify.entries", ELF::SHT_PROGBITS, Flags); 73*a34c753fSRafael Auler 74*a34c753fSRafael Auler // __bolt_hugify_init_ptr stores the poiter the hugify library needs to 75*a34c753fSRafael Auler // jump to after finishing the init code. 76*a34c753fSRafael Auler MCSymbol *InitPtr = BC.Ctx->getOrCreateSymbol("__bolt_hugify_init_ptr"); 77*a34c753fSRafael Auler 78*a34c753fSRafael Auler Section->setAlignment(llvm::Align(BC.RegularPageSize)); 79*a34c753fSRafael Auler Streamer.SwitchSection(Section); 80*a34c753fSRafael Auler 81*a34c753fSRafael Auler Streamer.emitLabel(InitPtr); 82*a34c753fSRafael Auler Streamer.emitSymbolAttribute(InitPtr, MCSymbolAttr::MCSA_Global); 83*a34c753fSRafael Auler Streamer.emitValue( 84*a34c753fSRafael Auler MCSymbolRefExpr::create(StartFunction->getSymbol(), *(BC.Ctx)), 85*a34c753fSRafael Auler /*Size=*/8); 86*a34c753fSRafael Auler } 87*a34c753fSRafael Auler 88*a34c753fSRafael Auler void HugifyRuntimeLibrary::link(BinaryContext &BC, StringRef ToolPath, 89*a34c753fSRafael Auler RuntimeDyld &RTDyld, 90*a34c753fSRafael Auler std::function<void(RuntimeDyld &)> OnLoad) { 91*a34c753fSRafael Auler std::string LibPath = getLibPath(ToolPath, opts::RuntimeHugifyLib); 92*a34c753fSRafael Auler loadLibrary(LibPath, RTDyld); 93*a34c753fSRafael Auler OnLoad(RTDyld); 94*a34c753fSRafael Auler RTDyld.finalizeWithMemoryManagerLocking(); 95*a34c753fSRafael Auler if (RTDyld.hasError()) { 96*a34c753fSRafael Auler outs() << "BOLT-ERROR: RTDyld failed: " << RTDyld.getErrorString() << "\n"; 97*a34c753fSRafael Auler exit(1); 98*a34c753fSRafael Auler } 99*a34c753fSRafael Auler 100*a34c753fSRafael Auler assert(!RuntimeStartAddress && 101*a34c753fSRafael Auler "We don't currently support linking multiple runtime libraries"); 102*a34c753fSRafael Auler RuntimeStartAddress = RTDyld.getSymbol("__bolt_hugify_self").getAddress(); 103*a34c753fSRafael Auler if (!RuntimeStartAddress) { 104*a34c753fSRafael Auler errs() << "BOLT-ERROR: instrumentation library does not define " 105*a34c753fSRafael Auler "__bolt_hugify_self: " 106*a34c753fSRafael Auler << LibPath << "\n"; 107*a34c753fSRafael Auler exit(1); 108*a34c753fSRafael Auler } 109*a34c753fSRafael Auler } 110