xref: /llvm-project/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp (revision a34c753fe709a624f5b087397fb05adeac2311e4)
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