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