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