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