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