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() = default; 24 25 void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) { 26 27 LLVM_DEBUG({ 28 dbgs() << "Starting link phase 1 for graph " << G->getName() << "\n"; 29 }); 30 31 // Prune and optimize the graph. 32 if (auto Err = runPasses(Passes.PrePrunePasses)) 33 return Ctx->notifyFailed(std::move(Err)); 34 35 LLVM_DEBUG({ 36 dbgs() << "Link graph \"" << G->getName() << "\" pre-pruning:\n"; 37 G->dump(dbgs()); 38 }); 39 40 prune(*G); 41 42 LLVM_DEBUG({ 43 dbgs() << "Link graph \"" << G->getName() << "\" post-pruning:\n"; 44 G->dump(dbgs()); 45 }); 46 47 // Run post-pruning passes. 48 if (auto Err = runPasses(Passes.PostPrunePasses)) 49 return Ctx->notifyFailed(std::move(Err)); 50 51 Ctx->getMemoryManager().allocate( 52 Ctx->getJITLinkDylib(), *G, 53 [S = std::move(Self)](AllocResult AR) mutable { 54 S->linkPhase2(std::move(S), std::move(AR)); 55 }); 56 } 57 58 void JITLinkerBase::linkPhase2(std::unique_ptr<JITLinkerBase> Self, 59 AllocResult AR) { 60 61 if (AR) 62 Alloc = std::move(*AR); 63 else 64 return Ctx->notifyFailed(AR.takeError()); 65 66 LLVM_DEBUG({ 67 dbgs() << "Link graph \"" << G->getName() 68 << "\" before post-allocation passes:\n"; 69 G->dump(dbgs()); 70 }); 71 72 // Run post-allocation passes. 73 if (auto Err = runPasses(Passes.PostAllocationPasses)) 74 return Ctx->notifyFailed(std::move(Err)); 75 76 // Notify client that the defined symbols have been assigned addresses. 77 LLVM_DEBUG(dbgs() << "Resolving symbols defined in " << G->getName() << "\n"); 78 79 if (auto Err = Ctx->notifyResolved(*G)) 80 return Ctx->notifyFailed(std::move(Err)); 81 82 auto ExternalSymbols = getExternalSymbolNames(); 83 84 // If there are no external symbols then proceed immediately with phase 3. 85 if (ExternalSymbols.empty()) { 86 LLVM_DEBUG({ 87 dbgs() << "No external symbols for " << G->getName() 88 << ". Proceeding immediately with link phase 3.\n"; 89 }); 90 Self->linkPhase3(std::move(Self), AsyncLookupResult()); 91 return; 92 } 93 94 // Otherwise look up the externals. 95 LLVM_DEBUG({ 96 dbgs() << "Issuing lookup for external symbols for " << G->getName() 97 << " (may trigger materialization/linking of other graphs)...\n"; 98 }); 99 100 // We're about to hand off ownership of ourself to the continuation. Grab a 101 // pointer to the context so that we can call it to initiate the lookup. 102 Ctx->lookup(std::move(ExternalSymbols), 103 createLookupContinuation( 104 [S = std::move(Self)]( 105 Expected<AsyncLookupResult> LookupResult) mutable { 106 S->linkPhase3(std::move(S), std::move(LookupResult)); 107 })); 108 } 109 110 void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self, 111 Expected<AsyncLookupResult> LR) { 112 113 LLVM_DEBUG({ 114 dbgs() << "Starting link phase 3 for graph " << G->getName() << "\n"; 115 }); 116 117 // If the lookup failed, bail out. 118 if (!LR) 119 return abandonAllocAndBailOut(std::move(Self), LR.takeError()); 120 121 // Assign addresses to external addressables. 122 applyLookupResult(*LR); 123 124 LLVM_DEBUG({ 125 dbgs() << "Link graph \"" << G->getName() 126 << "\" before pre-fixup passes:\n"; 127 G->dump(dbgs()); 128 }); 129 130 if (auto Err = runPasses(Passes.PreFixupPasses)) 131 return abandonAllocAndBailOut(std::move(Self), std::move(Err)); 132 133 LLVM_DEBUG({ 134 dbgs() << "Link graph \"" << G->getName() << "\" before copy-and-fixup:\n"; 135 G->dump(dbgs()); 136 }); 137 138 // Fix up block content. 139 if (auto Err = fixUpBlocks(*G)) 140 return abandonAllocAndBailOut(std::move(Self), std::move(Err)); 141 142 LLVM_DEBUG({ 143 dbgs() << "Link graph \"" << G->getName() << "\" after copy-and-fixup:\n"; 144 G->dump(dbgs()); 145 }); 146 147 if (auto Err = runPasses(Passes.PostFixupPasses)) 148 return abandonAllocAndBailOut(std::move(Self), std::move(Err)); 149 150 Alloc->finalize([S = std::move(Self)](FinalizeResult FR) mutable { 151 S->linkPhase4(std::move(S), std::move(FR)); 152 }); 153 } 154 155 void JITLinkerBase::linkPhase4(std::unique_ptr<JITLinkerBase> Self, 156 FinalizeResult FR) { 157 158 LLVM_DEBUG({ 159 dbgs() << "Starting link phase 4 for graph " << G->getName() << "\n"; 160 }); 161 162 if (!FR) 163 return Ctx->notifyFailed(FR.takeError()); 164 165 Ctx->notifyFinalized(std::move(*FR)); 166 167 LLVM_DEBUG({ dbgs() << "Link of graph " << G->getName() << " complete\n"; }); 168 } 169 170 Error JITLinkerBase::runPasses(LinkGraphPassList &Passes) { 171 for (auto &P : Passes) 172 if (auto Err = P(*G)) 173 return Err; 174 return Error::success(); 175 } 176 177 JITLinkContext::LookupMap JITLinkerBase::getExternalSymbolNames() const { 178 // Identify unresolved external symbols. 179 JITLinkContext::LookupMap UnresolvedExternals; 180 for (auto *Sym : G->external_symbols()) { 181 assert(!Sym->getAddress() && 182 "External has already been assigned an address"); 183 assert(Sym->getName() != StringRef() && Sym->getName() != "" && 184 "Externals must be named"); 185 SymbolLookupFlags LookupFlags = 186 Sym->getLinkage() == Linkage::Weak 187 ? SymbolLookupFlags::WeaklyReferencedSymbol 188 : SymbolLookupFlags::RequiredSymbol; 189 UnresolvedExternals[Sym->getName()] = LookupFlags; 190 } 191 return UnresolvedExternals; 192 } 193 194 void JITLinkerBase::applyLookupResult(AsyncLookupResult Result) { 195 for (auto *Sym : G->external_symbols()) { 196 assert(Sym->getOffset() == 0 && 197 "External symbol is not at the start of its addressable block"); 198 assert(!Sym->getAddress() && "Symbol already resolved"); 199 assert(!Sym->isDefined() && "Symbol being resolved is already defined"); 200 auto ResultI = Result.find(Sym->getName()); 201 if (ResultI != Result.end()) 202 Sym->getAddressable().setAddress( 203 orc::ExecutorAddr(ResultI->second.getAddress())); 204 else 205 assert(Sym->getLinkage() == Linkage::Weak && 206 "Failed to resolve non-weak reference"); 207 } 208 209 LLVM_DEBUG({ 210 dbgs() << "Externals after applying lookup result:\n"; 211 for (auto *Sym : G->external_symbols()) 212 dbgs() << " " << Sym->getName() << ": " 213 << formatv("{0:x16}", Sym->getAddress().getValue()) << "\n"; 214 }); 215 } 216 217 void JITLinkerBase::abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self, 218 Error Err) { 219 assert(Err && "Should not be bailing out on success value"); 220 assert(Alloc && "can not call abandonAllocAndBailOut before allocation"); 221 Alloc->abandon([S = std::move(Self), E1 = std::move(Err)](Error E2) mutable { 222 S->Ctx->notifyFailed(joinErrors(std::move(E1), std::move(E2))); 223 }); 224 } 225 226 void prune(LinkGraph &G) { 227 std::vector<Symbol *> Worklist; 228 DenseSet<Block *> VisitedBlocks; 229 230 // Build the initial worklist from all symbols initially live. 231 for (auto *Sym : G.defined_symbols()) 232 if (Sym->isLive()) 233 Worklist.push_back(Sym); 234 235 // Propagate live flags to all symbols reachable from the initial live set. 236 while (!Worklist.empty()) { 237 auto *Sym = Worklist.back(); 238 Worklist.pop_back(); 239 240 auto &B = Sym->getBlock(); 241 242 // Skip addressables that we've visited before. 243 if (VisitedBlocks.count(&B)) 244 continue; 245 246 VisitedBlocks.insert(&B); 247 248 for (auto &E : Sym->getBlock().edges()) { 249 // If the edge target is a defined symbol that is being newly marked live 250 // then add it to the worklist. 251 if (E.getTarget().isDefined() && !E.getTarget().isLive()) 252 Worklist.push_back(&E.getTarget()); 253 254 // Mark the target live. 255 E.getTarget().setLive(true); 256 } 257 } 258 259 // Collect all defined symbols to remove, then remove them. 260 { 261 LLVM_DEBUG(dbgs() << "Dead-stripping defined symbols:\n"); 262 std::vector<Symbol *> SymbolsToRemove; 263 for (auto *Sym : G.defined_symbols()) 264 if (!Sym->isLive()) 265 SymbolsToRemove.push_back(Sym); 266 for (auto *Sym : SymbolsToRemove) { 267 LLVM_DEBUG(dbgs() << " " << *Sym << "...\n"); 268 G.removeDefinedSymbol(*Sym); 269 } 270 } 271 272 // Delete any unused blocks. 273 { 274 LLVM_DEBUG(dbgs() << "Dead-stripping blocks:\n"); 275 std::vector<Block *> BlocksToRemove; 276 for (auto *B : G.blocks()) 277 if (!VisitedBlocks.count(B)) 278 BlocksToRemove.push_back(B); 279 for (auto *B : BlocksToRemove) { 280 LLVM_DEBUG(dbgs() << " " << *B << "...\n"); 281 G.removeBlock(*B); 282 } 283 } 284 285 // Collect all external symbols to remove, then remove them. 286 { 287 LLVM_DEBUG(dbgs() << "Removing unused external symbols:\n"); 288 std::vector<Symbol *> SymbolsToRemove; 289 for (auto *Sym : G.external_symbols()) 290 if (!Sym->isLive()) 291 SymbolsToRemove.push_back(Sym); 292 for (auto *Sym : SymbolsToRemove) { 293 LLVM_DEBUG(dbgs() << " " << *Sym << "...\n"); 294 G.removeExternalSymbol(*Sym); 295 } 296 } 297 } 298 299 } // end namespace jitlink 300 } // end namespace llvm 301