1 //===--------- JITLinkGeneric.cpp - Generic JIT linker utilities ----------===//
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 // Generic JITLinker utility class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "JITLinkGeneric.h"
14 
15 #include "llvm/Support/BinaryStreamReader.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 
18 #define DEBUG_TYPE "jitlink"
19 
20 namespace llvm {
21 namespace jitlink {
22 
23 JITLinkerBase::~JITLinkerBase() {}
24 
25 void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {
26 
27   // Build the link graph.
28   if (auto GraphOrErr = buildGraph(Ctx->getObjectBuffer()))
29     G = std::move(*GraphOrErr);
30   else
31     return Ctx->notifyFailed(GraphOrErr.takeError());
32   assert(G && "Graph should have been created by buildGraph above");
33 
34   // Prune and optimize the graph.
35   if (auto Err = runPasses(Passes.PrePrunePasses))
36     return Ctx->notifyFailed(std::move(Err));
37 
38   LLVM_DEBUG({
39     dbgs() << "Link graph \"" << G->getName() << "\" pre-pruning:\n";
40     dumpGraph(dbgs());
41   });
42 
43   prune(*G);
44 
45   LLVM_DEBUG({
46     dbgs() << "Link graph \"" << G->getName() << "\" post-pruning:\n";
47     dumpGraph(dbgs());
48   });
49 
50   // Run post-pruning passes.
51   if (auto Err = runPasses(Passes.PostPrunePasses))
52     return Ctx->notifyFailed(std::move(Err));
53 
54   // Sort blocks into segments.
55   auto Layout = layOutBlocks();
56 
57   // Allocate memory for segments.
58   if (auto Err = allocateSegments(Layout))
59     return Ctx->notifyFailed(std::move(Err));
60 
61   // Notify client that the defined symbols have been assigned addresses.
62   Ctx->notifyResolved(*G);
63 
64   auto ExternalSymbols = getExternalSymbolNames();
65 
66   // We're about to hand off ownership of ourself to the continuation. Grab a
67   // pointer to the context so that we can call it to initiate the lookup.
68   //
69   // FIXME: Once callee expressions are defined to be sequenced before argument
70   // expressions (c++17) we can simplify all this to:
71   //
72   // Ctx->lookup(std::move(UnresolvedExternals),
73   //             [Self=std::move(Self)](Expected<AsyncLookupResult> Result) {
74   //               Self->linkPhase2(std::move(Self), std::move(Result));
75   //             });
76   auto *TmpCtx = Ctx.get();
77   TmpCtx->lookup(std::move(ExternalSymbols),
78                  createLookupContinuation(
79                      [S = std::move(Self), L = std::move(Layout)](
80                          Expected<AsyncLookupResult> LookupResult) mutable {
81                        auto &TmpSelf = *S;
82                        TmpSelf.linkPhase2(std::move(S), std::move(LookupResult),
83                                           std::move(L));
84                      }));
85 }
86 
87 void JITLinkerBase::linkPhase2(std::unique_ptr<JITLinkerBase> Self,
88                                Expected<AsyncLookupResult> LR,
89                                SegmentLayoutMap Layout) {
90   // If the lookup failed, bail out.
91   if (!LR)
92     return deallocateAndBailOut(LR.takeError());
93 
94   // Assign addresses to external addressables.
95   applyLookupResult(*LR);
96 
97   LLVM_DEBUG({
98     dbgs() << "Link graph \"" << G->getName() << "\" before copy-and-fixup:\n";
99     dumpGraph(dbgs());
100   });
101 
102   // Copy block content to working memory and fix up.
103   if (auto Err = copyAndFixUpBlocks(Layout, *Alloc))
104     return deallocateAndBailOut(std::move(Err));
105 
106   LLVM_DEBUG({
107     dbgs() << "Link graph \"" << G->getName() << "\" after copy-and-fixup:\n";
108     dumpGraph(dbgs());
109   });
110 
111   if (auto Err = runPasses(Passes.PostFixupPasses))
112     return deallocateAndBailOut(std::move(Err));
113 
114   // FIXME: Use move capture once we have c++14.
115   auto *UnownedSelf = Self.release();
116   auto Phase3Continuation = [UnownedSelf](Error Err) {
117     std::unique_ptr<JITLinkerBase> Self(UnownedSelf);
118     UnownedSelf->linkPhase3(std::move(Self), std::move(Err));
119   };
120 
121   Alloc->finalizeAsync(std::move(Phase3Continuation));
122 }
123 
124 void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err) {
125   if (Err)
126     return deallocateAndBailOut(std::move(Err));
127   Ctx->notifyFinalized(std::move(Alloc));
128 }
129 
130 Error JITLinkerBase::runPasses(LinkGraphPassList &Passes) {
131   for (auto &P : Passes)
132     if (auto Err = P(*G))
133       return Err;
134   return Error::success();
135 }
136 
137 JITLinkerBase::SegmentLayoutMap JITLinkerBase::layOutBlocks() {
138 
139   SegmentLayoutMap Layout;
140 
141   /// Partition blocks based on permissions and content vs. zero-fill.
142   for (auto *B : G->blocks()) {
143     auto &SegLists = Layout[B->getSection().getProtectionFlags()];
144     if (!B->isZeroFill())
145       SegLists.ContentBlocks.push_back(B);
146     else
147       SegLists.ZeroFillBlocks.push_back(B);
148   }
149 
150   /// Sort blocks within each list.
151   for (auto &KV : Layout) {
152 
153     auto CompareBlocks = [](const Block *LHS, const Block *RHS) {
154       // Sort by section, address and size
155       if (LHS->getSection().getOrdinal() != RHS->getSection().getOrdinal())
156         return LHS->getSection().getOrdinal() < RHS->getSection().getOrdinal();
157       if (LHS->getAddress() != RHS->getAddress())
158         return LHS->getAddress() < RHS->getAddress();
159       return LHS->getSize() < RHS->getSize();
160     };
161 
162     auto &SegLists = KV.second;
163     llvm::sort(SegLists.ContentBlocks, CompareBlocks);
164     llvm::sort(SegLists.ZeroFillBlocks, CompareBlocks);
165   }
166 
167   LLVM_DEBUG({
168     dbgs() << "Segment ordering:\n";
169     for (auto &KV : Layout) {
170       dbgs() << "  Segment "
171              << static_cast<sys::Memory::ProtectionFlags>(KV.first) << ":\n";
172       auto &SL = KV.second;
173       for (auto &SIEntry :
174            {std::make_pair(&SL.ContentBlocks, "content block"),
175             std::make_pair(&SL.ZeroFillBlocks, "zero-fill block")}) {
176         dbgs() << "    " << SIEntry.second << ":\n";
177         for (auto *B : *SIEntry.first)
178           dbgs() << "      " << *B << "\n";
179       }
180     }
181   });
182 
183   return Layout;
184 }
185 
186 Error JITLinkerBase::allocateSegments(const SegmentLayoutMap &Layout) {
187 
188   // Compute segment sizes and allocate memory.
189   LLVM_DEBUG(dbgs() << "JIT linker requesting: { ");
190   JITLinkMemoryManager::SegmentsRequestMap Segments;
191   for (auto &KV : Layout) {
192     auto &Prot = KV.first;
193     auto &SegLists = KV.second;
194 
195     uint64_t SegAlign = 1;
196 
197     // Calculate segment content size.
198     size_t SegContentSize = 0;
199     for (auto *B : SegLists.ContentBlocks) {
200       SegAlign = std::max(SegAlign, B->getAlignment());
201       SegContentSize = alignToBlock(SegContentSize, *B);
202       SegContentSize += B->getSize();
203     }
204 
205     uint64_t SegZeroFillStart = SegContentSize;
206     uint64_t SegZeroFillEnd = SegZeroFillStart;
207 
208     for (auto *B : SegLists.ZeroFillBlocks) {
209       SegAlign = std::max(SegAlign, B->getAlignment());
210       SegZeroFillEnd = alignToBlock(SegZeroFillEnd, *B);
211       SegZeroFillEnd += B->getSize();
212     }
213 
214     Segments[Prot] = {SegAlign, SegContentSize,
215                       SegZeroFillEnd - SegZeroFillStart};
216 
217     LLVM_DEBUG({
218       dbgs() << (&KV == &*Layout.begin() ? "" : "; ")
219              << static_cast<sys::Memory::ProtectionFlags>(Prot)
220              << ": alignment = " << SegAlign
221              << ", content size = " << SegContentSize
222              << ", zero-fill size = " << (SegZeroFillEnd - SegZeroFillStart);
223     });
224   }
225   LLVM_DEBUG(dbgs() << " }\n");
226 
227   if (auto AllocOrErr = Ctx->getMemoryManager().allocate(Segments))
228     Alloc = std::move(*AllocOrErr);
229   else
230     return AllocOrErr.takeError();
231 
232   LLVM_DEBUG({
233     dbgs() << "JIT linker got working memory:\n";
234     for (auto &KV : Layout) {
235       auto Prot = static_cast<sys::Memory::ProtectionFlags>(KV.first);
236       dbgs() << "  " << Prot << ": "
237              << (const void *)Alloc->getWorkingMemory(Prot).data() << "\n";
238     }
239   });
240 
241   // Update block target addresses.
242   for (auto &KV : Layout) {
243     auto &Prot = KV.first;
244     auto &SL = KV.second;
245 
246     JITTargetAddress NextBlockAddr =
247         Alloc->getTargetMemory(static_cast<sys::Memory::ProtectionFlags>(Prot));
248 
249     for (auto *SIList : {&SL.ContentBlocks, &SL.ZeroFillBlocks})
250       for (auto *B : *SIList) {
251         NextBlockAddr = alignToBlock(NextBlockAddr, *B);
252         B->setAddress(NextBlockAddr);
253         NextBlockAddr += B->getSize();
254       }
255   }
256 
257   return Error::success();
258 }
259 
260 JITLinkContext::LookupMap JITLinkerBase::getExternalSymbolNames() const {
261   // Identify unresolved external symbols.
262   JITLinkContext::LookupMap UnresolvedExternals;
263   for (auto *Sym : G->external_symbols()) {
264     assert(Sym->getAddress() == 0 &&
265            "External has already been assigned an address");
266     assert(Sym->getName() != StringRef() && Sym->getName() != "" &&
267            "Externals must be named");
268     SymbolLookupFlags LookupFlags =
269         Sym->getLinkage() == Linkage::Weak
270             ? SymbolLookupFlags::WeaklyReferencedSymbol
271             : SymbolLookupFlags::RequiredSymbol;
272     UnresolvedExternals[Sym->getName()] = LookupFlags;
273   }
274   return UnresolvedExternals;
275 }
276 
277 void JITLinkerBase::applyLookupResult(AsyncLookupResult Result) {
278   for (auto *Sym : G->external_symbols()) {
279     assert(Sym->getOffset() == 0 &&
280            "External symbol is not at the start of its addressable block");
281     assert(Sym->getAddress() == 0 && "Symbol already resolved");
282     assert(!Sym->isDefined() && "Symbol being resolved is already defined");
283     auto ResultI = Result.find(Sym->getName());
284     if (ResultI != Result.end())
285       Sym->getAddressable().setAddress(ResultI->second.getAddress());
286     else
287       assert(Sym->getLinkage() == Linkage::Weak &&
288              "Failed to resolve non-weak reference");
289   }
290 
291   LLVM_DEBUG({
292     dbgs() << "Externals after applying lookup result:\n";
293     for (auto *Sym : G->external_symbols())
294       dbgs() << "  " << Sym->getName() << ": "
295              << formatv("{0:x16}", Sym->getAddress()) << "\n";
296   });
297   assert(llvm::all_of(G->external_symbols(),
298                       [](Symbol *Sym) {
299                         return Sym->getAddress() != 0 ||
300                                Sym->getLinkage() == Linkage::Weak;
301                       }) &&
302          "All strong external symbols should have been resolved by now");
303 }
304 
305 void JITLinkerBase::deallocateAndBailOut(Error Err) {
306   assert(Err && "Should not be bailing out on success value");
307   assert(Alloc && "can not call deallocateAndBailOut before allocation");
308   Ctx->notifyFailed(joinErrors(std::move(Err), Alloc->deallocate()));
309 }
310 
311 void JITLinkerBase::dumpGraph(raw_ostream &OS) {
312   assert(G && "Graph is not set yet");
313   G->dump(dbgs(), [this](Edge::Kind K) { return getEdgeKindName(K); });
314 }
315 
316 void prune(LinkGraph &G) {
317   std::vector<Symbol *> Worklist;
318   DenseSet<Block *> VisitedBlocks;
319 
320   // Build the initial worklist from all symbols initially live.
321   for (auto *Sym : G.defined_symbols())
322     if (Sym->isLive())
323       Worklist.push_back(Sym);
324 
325   // Propagate live flags to all symbols reachable from the initial live set.
326   while (!Worklist.empty()) {
327     auto *Sym = Worklist.back();
328     Worklist.pop_back();
329 
330     auto &B = Sym->getBlock();
331 
332     // Skip addressables that we've visited before.
333     if (VisitedBlocks.count(&B))
334       continue;
335 
336     VisitedBlocks.insert(&B);
337 
338     for (auto &E : Sym->getBlock().edges()) {
339       if (E.getTarget().isDefined() && !E.getTarget().isLive()) {
340         E.getTarget().setLive(true);
341         Worklist.push_back(&E.getTarget());
342       }
343     }
344   }
345 
346   // Collect all the symbols to remove, then remove them.
347   {
348     LLVM_DEBUG(dbgs() << "Dead-stripping symbols:\n");
349     std::vector<Symbol *> SymbolsToRemove;
350     for (auto *Sym : G.defined_symbols())
351       if (!Sym->isLive())
352         SymbolsToRemove.push_back(Sym);
353     for (auto *Sym : SymbolsToRemove) {
354       LLVM_DEBUG(dbgs() << "  " << *Sym << "...\n");
355       G.removeDefinedSymbol(*Sym);
356     }
357   }
358 
359   // Delete any unused blocks.
360   {
361     LLVM_DEBUG(dbgs() << "Dead-stripping blocks:\n");
362     std::vector<Block *> BlocksToRemove;
363     for (auto *B : G.blocks())
364       if (!VisitedBlocks.count(B))
365         BlocksToRemove.push_back(B);
366     for (auto *B : BlocksToRemove) {
367       LLVM_DEBUG(dbgs() << "  " << *B << "...\n");
368       G.removeBlock(*B);
369     }
370   }
371 }
372 
373 } // end namespace jitlink
374 } // end namespace llvm
375