xref: /llvm-project/bolt/lib/Rewrite/JITLinkLinker.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
1 //===- bolt/Rewrite/JITLinkLinker.cpp - BOLTLinker using JITLink ----------===//
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/Rewrite/JITLinkLinker.h"
10 #include "bolt/Core/BinaryContext.h"
11 #include "bolt/Core/BinaryData.h"
12 #include "bolt/Core/BinarySection.h"
13 #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
14 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
15 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
16 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
17 #include "llvm/Support/Debug.h"
18 
19 #define DEBUG_TYPE "bolt"
20 
21 namespace llvm {
22 namespace bolt {
23 
24 namespace {
25 
26 bool hasSymbols(const jitlink::Block &B) {
27   return llvm::any_of(B.getSection().symbols(),
28                       [&B](const auto &S) { return &S->getBlock() == &B; });
29 }
30 
31 /// Liveness in JITLink is based on symbols so sections that do not contain
32 /// any symbols will always be pruned. This pass adds anonymous symbols to
33 /// needed sections to prevent pruning.
34 Error markSectionsLive(jitlink::LinkGraph &G) {
35   for (auto &Section : G.sections()) {
36     // We only need allocatable sections.
37     if (Section.getMemLifetime() == orc::MemLifetime::NoAlloc)
38       continue;
39 
40     // Skip empty sections.
41     if (JITLinkLinker::sectionSize(Section) == 0)
42       continue;
43 
44     for (auto *Block : Section.blocks()) {
45       // No need to add symbols if it already has some.
46       if (hasSymbols(*Block))
47         continue;
48 
49       G.addAnonymousSymbol(*Block, /*Offset=*/0, /*Size=*/0,
50                            /*IsCallable=*/false, /*IsLive=*/true);
51     }
52   }
53 
54   return jitlink::markAllSymbolsLive(G);
55 }
56 
57 void reassignSectionAddress(jitlink::LinkGraph &LG,
58                             const BinarySection &BinSection, uint64_t Address) {
59   auto *JLSection = LG.findSectionByName(BinSection.getSectionID());
60   assert(JLSection && "cannot find section in LinkGraph");
61 
62   auto BlockAddress = Address;
63   for (auto *Block : JITLinkLinker::orderedBlocks(*JLSection)) {
64     // FIXME it would seem to make sense to align here. However, in
65     // non-relocation mode, we simply use the original address of functions
66     // which might not be aligned with the minimum alignment used by
67     // BinaryFunction (2). Example failing test when aligning:
68     // bolt/test/X86/addr32.s
69     Block->setAddress(orc::ExecutorAddr(BlockAddress));
70     BlockAddress += Block->getSize();
71   }
72 }
73 
74 } // anonymous namespace
75 
76 struct JITLinkLinker::Context : jitlink::JITLinkContext {
77   JITLinkLinker &Linker;
78   JITLinkLinker::SectionsMapper MapSections;
79 
80   Context(JITLinkLinker &Linker, JITLinkLinker::SectionsMapper MapSections)
81       : JITLinkContext(&Linker.Dylib), Linker(Linker),
82         MapSections(MapSections) {}
83 
84   jitlink::JITLinkMemoryManager &getMemoryManager() override {
85     return *Linker.MM;
86   }
87 
88   bool shouldAddDefaultTargetPasses(const Triple &TT) const override {
89     // The default passes manipulate DWARF sections in a way incompatible with
90     // BOLT.
91     // TODO check if we can actually use these passes to remove some of the
92     // DWARF manipulation done in BOLT.
93     return false;
94   }
95 
96   Error modifyPassConfig(jitlink::LinkGraph &G,
97                          jitlink::PassConfiguration &Config) override {
98     Config.PrePrunePasses.push_back(markSectionsLive);
99     Config.PostAllocationPasses.push_back([this](auto &G) {
100       MapSections([&G](const BinarySection &Section, uint64_t Address) {
101         reassignSectionAddress(G, Section, Address);
102       });
103       return Error::success();
104     });
105 
106     if (G.getTargetTriple().isRISCV()) {
107       Config.PostAllocationPasses.push_back(
108           jitlink::createRelaxationPass_ELF_riscv());
109     }
110 
111     return Error::success();
112   }
113 
114   void notifyFailed(Error Err) override {
115     errs() << "BOLT-ERROR: JITLink failed: " << Err << '\n';
116     exit(1);
117   }
118 
119   void
120   lookup(const LookupMap &Symbols,
121          std::unique_ptr<jitlink::JITLinkAsyncLookupContinuation> LC) override {
122     jitlink::AsyncLookupResult AllResults;
123 
124     for (const auto &Symbol : Symbols) {
125       std::string SymName = (*Symbol.first).str();
126       LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName << "\n");
127 
128       if (auto Address = Linker.lookupSymbol(SymName)) {
129         LLVM_DEBUG(dbgs() << "Resolved to address 0x"
130                           << Twine::utohexstr(*Address) << "\n");
131         AllResults[Symbol.first] = orc::ExecutorSymbolDef(
132             orc::ExecutorAddr(*Address), JITSymbolFlags());
133         continue;
134       }
135 
136       if (const BinaryData *I = Linker.BC.getBinaryDataByName(SymName)) {
137         uint64_t Address = I->isMoved() && !I->isJumpTable()
138                                ? I->getOutputAddress()
139                                : I->getAddress();
140         LLVM_DEBUG(dbgs() << "Resolved to address 0x"
141                           << Twine::utohexstr(Address) << "\n");
142         AllResults[Symbol.first] = orc::ExecutorSymbolDef(
143             orc::ExecutorAddr(Address), JITSymbolFlags());
144         continue;
145       }
146 
147       if (Linker.BC.isGOTSymbol(SymName)) {
148         if (const BinaryData *I = Linker.BC.getGOTSymbol()) {
149           uint64_t Address =
150               I->isMoved() ? I->getOutputAddress() : I->getAddress();
151           LLVM_DEBUG(dbgs() << "Resolved to address 0x"
152                             << Twine::utohexstr(Address) << "\n");
153           AllResults[Symbol.first] = orc::ExecutorSymbolDef(
154               orc::ExecutorAddr(Address), JITSymbolFlags());
155           continue;
156         }
157       }
158 
159       LLVM_DEBUG(dbgs() << "Resolved to address 0x0\n");
160       AllResults[Symbol.first] =
161           orc::ExecutorSymbolDef(orc::ExecutorAddr(0), JITSymbolFlags());
162     }
163 
164     LC->run(std::move(AllResults));
165   }
166 
167   Error notifyResolved(jitlink::LinkGraph &G) override {
168     for (auto *Symbol : G.defined_symbols()) {
169       SymbolInfo Info{Symbol->getAddress().getValue(), Symbol->getSize()};
170       auto Name =
171           Symbol->hasName() ? (*Symbol->getName()).str() : std::string();
172       Linker.Symtab.insert({std::move(Name), Info});
173     }
174 
175     return Error::success();
176   }
177 
178   void notifyFinalized(
179       jitlink::JITLinkMemoryManager::FinalizedAlloc Alloc) override {
180     if (Alloc)
181       Linker.Allocs.push_back(std::move(Alloc));
182     ++Linker.MM->ObjectsLoaded;
183   }
184 };
185 
186 JITLinkLinker::JITLinkLinker(BinaryContext &BC,
187                              std::unique_ptr<ExecutableFileMemoryManager> MM)
188     : BC(BC), MM(std::move(MM)) {}
189 
190 JITLinkLinker::~JITLinkLinker() { cantFail(MM->deallocate(std::move(Allocs))); }
191 
192 void JITLinkLinker::loadObject(MemoryBufferRef Obj,
193                                SectionsMapper MapSections) {
194   auto LG = jitlink::createLinkGraphFromObject(Obj, BC.getSymbolStringPool());
195   if (auto E = LG.takeError()) {
196     errs() << "BOLT-ERROR: JITLink failed: " << E << '\n';
197     exit(1);
198   }
199 
200   if ((*LG)->getTargetTriple().getArch() != BC.TheTriple->getArch()) {
201     errs() << "BOLT-ERROR: linking object with arch "
202            << (*LG)->getTargetTriple().getArchName()
203            << " into context with arch " << BC.TheTriple->getArchName() << "\n";
204     exit(1);
205   }
206 
207   auto Ctx = std::make_unique<Context>(*this, MapSections);
208   jitlink::link(std::move(*LG), std::move(Ctx));
209 }
210 
211 std::optional<JITLinkLinker::SymbolInfo>
212 JITLinkLinker::lookupSymbolInfo(StringRef Name) const {
213   auto It = Symtab.find(Name.data());
214   if (It == Symtab.end())
215     return std::nullopt;
216 
217   return It->second;
218 }
219 
220 SmallVector<jitlink::Block *, 2>
221 JITLinkLinker::orderedBlocks(const jitlink::Section &Section) {
222   SmallVector<jitlink::Block *, 2> Blocks(Section.blocks());
223   llvm::sort(Blocks, [](const auto *LHS, const auto *RHS) {
224     return LHS->getAddress() < RHS->getAddress();
225   });
226   return Blocks;
227 }
228 
229 size_t JITLinkLinker::sectionSize(const jitlink::Section &Section) {
230   size_t Size = 0;
231 
232   for (const auto *Block : orderedBlocks(Section)) {
233     Size = jitlink::alignToBlock(Size, *Block);
234     Size += Block->getSize();
235   }
236 
237   return Size;
238 }
239 
240 } // namespace bolt
241 } // namespace llvm
242