1 //===------ ELFNixPlatform.cpp - Utilities for executing MachO in Orc -----===// 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 "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" 10 11 #include "llvm/BinaryFormat/ELF.h" 12 #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" 13 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 14 #include "llvm/ExecutionEngine/Orc/DebugUtils.h" 15 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 16 #include "llvm/Support/BinaryByteStream.h" 17 #include "llvm/Support/Debug.h" 18 19 #define DEBUG_TYPE "orc" 20 21 using namespace llvm; 22 using namespace llvm::orc; 23 using namespace llvm::orc::shared; 24 25 namespace { 26 27 class DSOHandleMaterializationUnit : public MaterializationUnit { 28 public: 29 DSOHandleMaterializationUnit(ELFNixPlatform &ENP, 30 const SymbolStringPtr &DSOHandleSymbol) 31 : MaterializationUnit( 32 createDSOHandleSectionInterface(ENP, DSOHandleSymbol)), 33 ENP(ENP) {} 34 35 StringRef getName() const override { return "DSOHandleMU"; } 36 37 void materialize(std::unique_ptr<MaterializationResponsibility> R) override { 38 unsigned PointerSize; 39 support::endianness Endianness; 40 jitlink::Edge::Kind EdgeKind; 41 const auto &TT = 42 ENP.getExecutionSession().getExecutorProcessControl().getTargetTriple(); 43 44 switch (TT.getArch()) { 45 case Triple::x86_64: 46 PointerSize = 8; 47 Endianness = support::endianness::little; 48 EdgeKind = jitlink::x86_64::Pointer64; 49 break; 50 default: 51 llvm_unreachable("Unrecognized architecture"); 52 } 53 54 // void *__dso_handle = &__dso_handle; 55 auto G = std::make_unique<jitlink::LinkGraph>( 56 "<DSOHandleMU>", TT, PointerSize, Endianness, 57 jitlink::getGenericEdgeKindName); 58 auto &DSOHandleSection = 59 G->createSection(".data.__dso_handle", jitlink::MemProt::Read); 60 auto &DSOHandleBlock = G->createContentBlock( 61 DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(), 62 8, 0); 63 auto &DSOHandleSymbol = G->addDefinedSymbol( 64 DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(), 65 jitlink::Linkage::Strong, jitlink::Scope::Default, false, true); 66 DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0); 67 68 ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G)); 69 } 70 71 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} 72 73 private: 74 static MaterializationUnit::Interface 75 createDSOHandleSectionInterface(ELFNixPlatform &ENP, 76 const SymbolStringPtr &DSOHandleSymbol) { 77 SymbolFlagsMap SymbolFlags; 78 SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported; 79 return MaterializationUnit::Interface(std::move(SymbolFlags), 80 DSOHandleSymbol); 81 } 82 83 ArrayRef<char> getDSOHandleContent(size_t PointerSize) { 84 static const char Content[8] = {0}; 85 assert(PointerSize <= sizeof Content); 86 return {Content, PointerSize}; 87 } 88 89 ELFNixPlatform &ENP; 90 }; 91 92 StringRef EHFrameSectionName = ".eh_frame"; 93 StringRef InitArrayFuncSectionName = ".init_array"; 94 95 StringRef ThreadBSSSectionName = ".tbss"; 96 StringRef ThreadDataSectionName = ".tdata"; 97 98 StringRef InitSectionNames[] = {InitArrayFuncSectionName}; 99 100 } // end anonymous namespace 101 102 namespace llvm { 103 namespace orc { 104 105 Expected<std::unique_ptr<ELFNixPlatform>> 106 ELFNixPlatform::Create(ExecutionSession &ES, 107 ObjectLinkingLayer &ObjLinkingLayer, 108 JITDylib &PlatformJD, const char *OrcRuntimePath, 109 Optional<SymbolAliasMap> RuntimeAliases) { 110 111 auto &EPC = ES.getExecutorProcessControl(); 112 113 // If the target is not supported then bail out immediately. 114 if (!supportedTarget(EPC.getTargetTriple())) 115 return make_error<StringError>("Unsupported ELFNixPlatform triple: " + 116 EPC.getTargetTriple().str(), 117 inconvertibleErrorCode()); 118 119 // Create default aliases if the caller didn't supply any. 120 if (!RuntimeAliases) 121 RuntimeAliases = standardPlatformAliases(ES); 122 123 // Define the aliases. 124 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases)))) 125 return std::move(Err); 126 127 // Add JIT-dispatch function support symbols. 128 if (auto Err = PlatformJD.define(absoluteSymbols( 129 {{ES.intern("__orc_rt_jit_dispatch"), 130 {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(), 131 JITSymbolFlags::Exported}}, 132 {ES.intern("__orc_rt_jit_dispatch_ctx"), 133 {EPC.getJITDispatchInfo().JITDispatchContext.getValue(), 134 JITSymbolFlags::Exported}}}))) 135 return std::move(Err); 136 137 // Create a generator for the ORC runtime archive. 138 auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load( 139 ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple()); 140 if (!OrcRuntimeArchiveGenerator) 141 return OrcRuntimeArchiveGenerator.takeError(); 142 143 // Create the instance. 144 Error Err = Error::success(); 145 auto P = std::unique_ptr<ELFNixPlatform>( 146 new ELFNixPlatform(ES, ObjLinkingLayer, PlatformJD, 147 std::move(*OrcRuntimeArchiveGenerator), Err)); 148 if (Err) 149 return std::move(Err); 150 return std::move(P); 151 } 152 153 Error ELFNixPlatform::setupJITDylib(JITDylib &JD) { 154 return JD.define( 155 std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol)); 156 } 157 158 Error ELFNixPlatform::teardownJITDylib(JITDylib &JD) { 159 return Error::success(); 160 } 161 162 Error ELFNixPlatform::notifyAdding(ResourceTracker &RT, 163 const MaterializationUnit &MU) { 164 auto &JD = RT.getJITDylib(); 165 const auto &InitSym = MU.getInitializerSymbol(); 166 if (!InitSym) 167 return Error::success(); 168 169 RegisteredInitSymbols[&JD].add(InitSym, 170 SymbolLookupFlags::WeaklyReferencedSymbol); 171 LLVM_DEBUG({ 172 dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym 173 << " for MU " << MU.getName() << "\n"; 174 }); 175 return Error::success(); 176 } 177 178 Error ELFNixPlatform::notifyRemoving(ResourceTracker &RT) { 179 llvm_unreachable("Not supported yet"); 180 } 181 182 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, 183 ArrayRef<std::pair<const char *, const char *>> AL) { 184 for (auto &KV : AL) { 185 auto AliasName = ES.intern(KV.first); 186 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map"); 187 Aliases[std::move(AliasName)] = {ES.intern(KV.second), 188 JITSymbolFlags::Exported}; 189 } 190 } 191 192 SymbolAliasMap ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES) { 193 SymbolAliasMap Aliases; 194 addAliases(ES, Aliases, requiredCXXAliases()); 195 addAliases(ES, Aliases, standardRuntimeUtilityAliases()); 196 return Aliases; 197 } 198 199 ArrayRef<std::pair<const char *, const char *>> 200 ELFNixPlatform::requiredCXXAliases() { 201 static const std::pair<const char *, const char *> RequiredCXXAliases[] = { 202 {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"}, 203 {"atexit", "__orc_rt_elfnix_atexit"}}; 204 205 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases); 206 } 207 208 ArrayRef<std::pair<const char *, const char *>> 209 ELFNixPlatform::standardRuntimeUtilityAliases() { 210 static const std::pair<const char *, const char *> 211 StandardRuntimeUtilityAliases[] = { 212 {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"}, 213 {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}}; 214 215 return ArrayRef<std::pair<const char *, const char *>>( 216 StandardRuntimeUtilityAliases); 217 } 218 219 bool ELFNixPlatform::isInitializerSection(StringRef SecName) { 220 for (auto &Name : InitSectionNames) { 221 if (Name.equals(SecName)) 222 return true; 223 } 224 return false; 225 } 226 227 bool ELFNixPlatform::supportedTarget(const Triple &TT) { 228 switch (TT.getArch()) { 229 case Triple::x86_64: 230 return true; 231 default: 232 return false; 233 } 234 } 235 236 ELFNixPlatform::ELFNixPlatform( 237 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 238 JITDylib &PlatformJD, 239 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err) 240 : ES(ES), ObjLinkingLayer(ObjLinkingLayer), 241 DSOHandleSymbol(ES.intern("__dso_handle")) { 242 ErrorAsOutParameter _(&Err); 243 244 ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this)); 245 246 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator)); 247 248 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating 249 // the platform now), so set it up. 250 if (auto E2 = setupJITDylib(PlatformJD)) { 251 Err = std::move(E2); 252 return; 253 } 254 255 RegisteredInitSymbols[&PlatformJD].add( 256 DSOHandleSymbol, SymbolLookupFlags::WeaklyReferencedSymbol); 257 258 // Associate wrapper function tags with JIT-side function implementations. 259 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) { 260 Err = std::move(E2); 261 return; 262 } 263 264 // Lookup addresses of runtime functions callable by the platform, 265 // call the platform bootstrap function to initialize the platform-state 266 // object in the executor. 267 if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) { 268 Err = std::move(E2); 269 return; 270 } 271 } 272 273 Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { 274 ExecutionSession::JITDispatchHandlerAssociationMap WFs; 275 276 using GetInitializersSPSSig = 277 SPSExpected<SPSELFNixJITDylibInitializerSequence>(SPSString); 278 WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] = 279 ES.wrapAsyncWithSPS<GetInitializersSPSSig>( 280 this, &ELFNixPlatform::rt_getInitializers); 281 282 using GetDeinitializersSPSSig = 283 SPSExpected<SPSELFJITDylibDeinitializerSequence>(SPSExecutorAddr); 284 WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] = 285 ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>( 286 this, &ELFNixPlatform::rt_getDeinitializers); 287 288 using LookupSymbolSPSSig = 289 SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString); 290 WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] = 291 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this, 292 &ELFNixPlatform::rt_lookupSymbol); 293 294 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); 295 } 296 297 void ELFNixPlatform::getInitializersBuildSequencePhase( 298 SendInitializerSequenceFn SendResult, JITDylib &JD, 299 std::vector<JITDylibSP> DFSLinkOrder) { 300 ELFNixJITDylibInitializerSequence FullInitSeq; 301 { 302 std::lock_guard<std::mutex> Lock(PlatformMutex); 303 for (auto &InitJD : reverse(DFSLinkOrder)) { 304 LLVM_DEBUG({ 305 dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName() 306 << "\" to sequence\n"; 307 }); 308 auto ISItr = InitSeqs.find(InitJD.get()); 309 if (ISItr != InitSeqs.end()) { 310 FullInitSeq.emplace_back(std::move(ISItr->second)); 311 InitSeqs.erase(ISItr); 312 } 313 } 314 } 315 316 SendResult(std::move(FullInitSeq)); 317 } 318 319 void ELFNixPlatform::getInitializersLookupPhase( 320 SendInitializerSequenceFn SendResult, JITDylib &JD) { 321 322 auto DFSLinkOrder = JD.getDFSLinkOrder(); 323 if (!DFSLinkOrder) { 324 SendResult(DFSLinkOrder.takeError()); 325 return; 326 } 327 328 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; 329 ES.runSessionLocked([&]() { 330 for (auto &InitJD : *DFSLinkOrder) { 331 auto RISItr = RegisteredInitSymbols.find(InitJD.get()); 332 if (RISItr != RegisteredInitSymbols.end()) { 333 NewInitSymbols[InitJD.get()] = std::move(RISItr->second); 334 RegisteredInitSymbols.erase(RISItr); 335 } 336 } 337 }); 338 339 // If there are no further init symbols to look up then move on to the next 340 // phase. 341 if (NewInitSymbols.empty()) { 342 getInitializersBuildSequencePhase(std::move(SendResult), JD, 343 std::move(*DFSLinkOrder)); 344 return; 345 } 346 347 // Otherwise issue a lookup and re-run this phase when it completes. 348 lookupInitSymbolsAsync( 349 [this, SendResult = std::move(SendResult), &JD](Error Err) mutable { 350 if (Err) 351 SendResult(std::move(Err)); 352 else 353 getInitializersLookupPhase(std::move(SendResult), JD); 354 }, 355 ES, std::move(NewInitSymbols)); 356 } 357 358 void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult, 359 StringRef JDName) { 360 LLVM_DEBUG({ 361 dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n"; 362 }); 363 364 JITDylib *JD = ES.getJITDylibByName(JDName); 365 if (!JD) { 366 LLVM_DEBUG({ 367 dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n"; 368 }); 369 SendResult(make_error<StringError>("No JITDylib named " + JDName, 370 inconvertibleErrorCode())); 371 return; 372 } 373 374 getInitializersLookupPhase(std::move(SendResult), *JD); 375 } 376 377 void ELFNixPlatform::rt_getDeinitializers( 378 SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) { 379 LLVM_DEBUG({ 380 dbgs() << "ELFNixPlatform::rt_getDeinitializers(\"" 381 << formatv("{0:x}", Handle.getValue()) << "\")\n"; 382 }); 383 384 JITDylib *JD = nullptr; 385 386 { 387 std::lock_guard<std::mutex> Lock(PlatformMutex); 388 auto I = HandleAddrToJITDylib.find(Handle); 389 if (I != HandleAddrToJITDylib.end()) 390 JD = I->second; 391 } 392 393 if (!JD) { 394 LLVM_DEBUG({ 395 dbgs() << " No JITDylib for handle " 396 << formatv("{0:x}", Handle.getValue()) << "\n"; 397 }); 398 SendResult(make_error<StringError>("No JITDylib associated with handle " + 399 formatv("{0:x}", Handle.getValue()), 400 inconvertibleErrorCode())); 401 return; 402 } 403 404 SendResult(ELFNixJITDylibDeinitializerSequence()); 405 } 406 407 void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, 408 ExecutorAddr Handle, 409 StringRef SymbolName) { 410 LLVM_DEBUG({ 411 dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" 412 << formatv("{0:x}", Handle.getValue()) << "\")\n"; 413 }); 414 415 JITDylib *JD = nullptr; 416 417 { 418 std::lock_guard<std::mutex> Lock(PlatformMutex); 419 auto I = HandleAddrToJITDylib.find(Handle); 420 if (I != HandleAddrToJITDylib.end()) 421 JD = I->second; 422 } 423 424 if (!JD) { 425 LLVM_DEBUG({ 426 dbgs() << " No JITDylib for handle " 427 << formatv("{0:x}", Handle.getValue()) << "\n"; 428 }); 429 SendResult(make_error<StringError>("No JITDylib associated with handle " + 430 formatv("{0:x}", Handle.getValue()), 431 inconvertibleErrorCode())); 432 return; 433 } 434 435 // Use functor class to work around XL build compiler issue on AIX. 436 class RtLookupNotifyComplete { 437 public: 438 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult) 439 : SendResult(std::move(SendResult)) {} 440 void operator()(Expected<SymbolMap> Result) { 441 if (Result) { 442 assert(Result->size() == 1 && "Unexpected result map count"); 443 SendResult(ExecutorAddr(Result->begin()->second.getAddress())); 444 } else { 445 SendResult(Result.takeError()); 446 } 447 } 448 449 private: 450 SendSymbolAddressFn SendResult; 451 }; 452 453 ES.lookup( 454 LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 455 SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready, 456 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister); 457 } 458 459 Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) { 460 461 std::pair<const char *, ExecutorAddr *> Symbols[] = { 462 {"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap}, 463 {"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown}, 464 {"__orc_rt_elfnix_register_object_sections", 465 &orc_rt_elfnix_register_object_sections}, 466 {"__orc_rt_elfnix_create_pthread_key", 467 &orc_rt_elfnix_create_pthread_key}}; 468 469 SymbolLookupSet RuntimeSymbols; 470 std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord; 471 for (const auto &KV : Symbols) { 472 auto Name = ES.intern(KV.first); 473 RuntimeSymbols.add(Name); 474 AddrsToRecord.push_back({std::move(Name), KV.second}); 475 } 476 477 auto RuntimeSymbolAddrs = ES.lookup( 478 {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols); 479 if (!RuntimeSymbolAddrs) 480 return RuntimeSymbolAddrs.takeError(); 481 482 for (const auto &KV : AddrsToRecord) { 483 auto &Name = KV.first; 484 assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?"); 485 KV.second->setValue((*RuntimeSymbolAddrs)[Name].getAddress()); 486 } 487 488 auto PJDDSOHandle = ES.lookup( 489 {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol); 490 if (!PJDDSOHandle) 491 return PJDDSOHandle.takeError(); 492 493 if (auto Err = ES.callSPSWrapper<void(uint64_t)>( 494 orc_rt_elfnix_platform_bootstrap, PJDDSOHandle->getAddress())) 495 return Err; 496 497 // FIXME: Ordering is fuzzy here. We're probably best off saying 498 // "behavior is undefined if code that uses the runtime is added before 499 // the platform constructor returns", then move all this to the constructor. 500 RuntimeBootstrapped = true; 501 std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs; 502 { 503 std::lock_guard<std::mutex> Lock(PlatformMutex); 504 DeferredPOSRs = std::move(BootstrapPOSRs); 505 } 506 507 for (auto &D : DeferredPOSRs) 508 if (auto Err = registerPerObjectSections(D)) 509 return Err; 510 511 return Error::success(); 512 } 513 514 Error ELFNixPlatform::registerInitInfo( 515 JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) { 516 517 std::unique_lock<std::mutex> Lock(PlatformMutex); 518 519 ELFNixJITDylibInitializers *InitSeq = nullptr; 520 { 521 auto I = InitSeqs.find(&JD); 522 if (I == InitSeqs.end()) { 523 // If there's no init sequence entry yet then we need to look up the 524 // header symbol to force creation of one. 525 Lock.unlock(); 526 527 auto SearchOrder = 528 JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; }); 529 if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError()) 530 return Err; 531 532 Lock.lock(); 533 I = InitSeqs.find(&JD); 534 assert(I != InitSeqs.end() && 535 "Entry missing after header symbol lookup?"); 536 } 537 InitSeq = &I->second; 538 } 539 540 for (auto *Sec : InitSections) { 541 // FIXME: Avoid copy here. 542 jitlink::SectionRange R(*Sec); 543 InitSeq->InitSections[Sec->getName()].push_back( 544 {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())}); 545 } 546 547 return Error::success(); 548 } 549 550 Error ELFNixPlatform::registerPerObjectSections( 551 const ELFPerObjectSectionsToRegister &POSR) { 552 553 if (!orc_rt_elfnix_register_object_sections) 554 return make_error<StringError>("Attempting to register per-object " 555 "sections, but runtime support has not " 556 "been loaded yet", 557 inconvertibleErrorCode()); 558 559 Error ErrResult = Error::success(); 560 if (auto Err = ES.callSPSWrapper<shared::SPSError( 561 SPSELFPerObjectSectionsToRegister)>( 562 orc_rt_elfnix_register_object_sections, ErrResult, POSR)) 563 return Err; 564 return ErrResult; 565 } 566 567 Expected<uint64_t> ELFNixPlatform::createPThreadKey() { 568 if (!orc_rt_elfnix_create_pthread_key) 569 return make_error<StringError>( 570 "Attempting to create pthread key in target, but runtime support has " 571 "not been loaded yet", 572 inconvertibleErrorCode()); 573 574 Expected<uint64_t> Result(0); 575 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( 576 orc_rt_elfnix_create_pthread_key, Result)) 577 return std::move(Err); 578 return Result; 579 } 580 581 void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig( 582 MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 583 jitlink::PassConfiguration &Config) { 584 585 // If the initializer symbol is the __dso_handle symbol then just add 586 // the DSO handle support passes. 587 if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) { 588 addDSOHandleSupportPasses(MR, Config); 589 // The DSOHandle materialization unit doesn't require any other 590 // support, so we can bail out early. 591 return; 592 } 593 594 // If the object contains initializers then add passes to record them. 595 if (MR.getInitializerSymbol()) 596 addInitializerSupportPasses(MR, Config); 597 598 // Add passes for eh-frame and TLV support. 599 addEHAndTLVSupportPasses(MR, Config); 600 } 601 602 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap 603 ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies( 604 MaterializationResponsibility &MR) { 605 std::lock_guard<std::mutex> Lock(PluginMutex); 606 auto I = InitSymbolDeps.find(&MR); 607 if (I != InitSymbolDeps.end()) { 608 SyntheticSymbolDependenciesMap Result; 609 Result[MR.getInitializerSymbol()] = std::move(I->second); 610 InitSymbolDeps.erase(&MR); 611 return Result; 612 } 613 return SyntheticSymbolDependenciesMap(); 614 } 615 616 void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses( 617 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 618 619 /// Preserve init sections. 620 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error { 621 if (auto Err = preserveInitSections(G, MR)) 622 return Err; 623 return Error::success(); 624 }); 625 626 Config.PostFixupPasses.push_back( 627 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { 628 return registerInitSections(G, JD); 629 }); 630 } 631 632 void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses( 633 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 634 635 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()]( 636 jitlink::LinkGraph &G) -> Error { 637 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { 638 return Sym->getName() == *MP.DSOHandleSymbol; 639 }); 640 assert(I != G.defined_symbols().end() && "Missing DSO handle symbol"); 641 { 642 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 643 auto HandleAddr = (*I)->getAddress(); 644 MP.HandleAddrToJITDylib[HandleAddr] = &JD; 645 assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists"); 646 MP.InitSeqs.insert(std::make_pair( 647 &JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr))); 648 } 649 return Error::success(); 650 }); 651 } 652 653 void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses( 654 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) { 655 656 // Insert TLV lowering at the start of the PostPrunePasses, since we want 657 // it to run before GOT/PLT lowering. 658 659 // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build 660 // pass has done. Because the TLS descriptor need to be allocate in GOT. 661 Config.PostPrunePasses.push_back( 662 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { 663 return fixTLVSectionsAndEdges(G, JD); 664 }); 665 666 // Add a pass to register the final addresses of the eh-frame and TLV sections 667 // with the runtime. 668 Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { 669 ELFPerObjectSectionsToRegister POSR; 670 671 if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) { 672 jitlink::SectionRange R(*EHFrameSection); 673 if (!R.empty()) 674 POSR.EHFrameSection = {ExecutorAddr(R.getStart()), 675 ExecutorAddr(R.getEnd())}; 676 } 677 678 // Get a pointer to the thread data section if there is one. It will be used 679 // below. 680 jitlink::Section *ThreadDataSection = 681 G.findSectionByName(ThreadDataSectionName); 682 683 // Handle thread BSS section if there is one. 684 if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) { 685 // If there's already a thread data section in this graph then merge the 686 // thread BSS section content into it, otherwise just treat the thread 687 // BSS section as the thread data section. 688 if (ThreadDataSection) 689 G.mergeSections(*ThreadDataSection, *ThreadBSSSection); 690 else 691 ThreadDataSection = ThreadBSSSection; 692 } 693 694 // Having merged thread BSS (if present) and thread data (if present), 695 // record the resulting section range. 696 if (ThreadDataSection) { 697 jitlink::SectionRange R(*ThreadDataSection); 698 if (!R.empty()) 699 POSR.ThreadDataSection = {ExecutorAddr(R.getStart()), 700 ExecutorAddr(R.getEnd())}; 701 } 702 703 if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) { 704 705 // If we're still bootstrapping the runtime then just record this 706 // frame for now. 707 if (!MP.RuntimeBootstrapped) { 708 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 709 MP.BootstrapPOSRs.push_back(POSR); 710 return Error::success(); 711 } 712 713 // Otherwise register it immediately. 714 if (auto Err = MP.registerPerObjectSections(POSR)) 715 return Err; 716 } 717 718 return Error::success(); 719 }); 720 } 721 722 Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections( 723 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 724 725 JITLinkSymbolSet InitSectionSymbols; 726 for (auto &InitSectionName : InitSectionNames) { 727 // Skip non-init sections. 728 auto *InitSection = G.findSectionByName(InitSectionName); 729 if (!InitSection) 730 continue; 731 732 // Make a pass over live symbols in the section: those blocks are already 733 // preserved. 734 DenseSet<jitlink::Block *> AlreadyLiveBlocks; 735 for (auto &Sym : InitSection->symbols()) { 736 auto &B = Sym->getBlock(); 737 if (Sym->isLive() && Sym->getOffset() == 0 && 738 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) { 739 InitSectionSymbols.insert(Sym); 740 AlreadyLiveBlocks.insert(&B); 741 } 742 } 743 744 // Add anonymous symbols to preserve any not-already-preserved blocks. 745 for (auto *B : InitSection->blocks()) 746 if (!AlreadyLiveBlocks.count(B)) 747 InitSectionSymbols.insert( 748 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true)); 749 } 750 751 if (!InitSectionSymbols.empty()) { 752 std::lock_guard<std::mutex> Lock(PluginMutex); 753 InitSymbolDeps[&MR] = std::move(InitSectionSymbols); 754 } 755 756 return Error::success(); 757 } 758 759 Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections( 760 jitlink::LinkGraph &G, JITDylib &JD) { 761 762 SmallVector<jitlink::Section *> InitSections; 763 764 LLVM_DEBUG({ dbgs() << "ELFNixPlatform::registerInitSections\n"; }); 765 766 for (auto InitSectionName : InitSectionNames) { 767 if (auto *Sec = G.findSectionByName(InitSectionName)) { 768 InitSections.push_back(Sec); 769 } 770 } 771 772 // Dump the scraped inits. 773 LLVM_DEBUG({ 774 dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n"; 775 for (auto *Sec : InitSections) { 776 jitlink::SectionRange R(*Sec); 777 dbgs() << " " << Sec->getName() << ": " 778 << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n"; 779 } 780 }); 781 782 return MP.registerInitInfo(JD, InitSections); 783 } 784 785 Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges( 786 jitlink::LinkGraph &G, JITDylib &JD) { 787 788 // TODO implement TLV support 789 for (auto *Sym : G.external_symbols()) 790 if (Sym->getName() == "__tls_get_addr") { 791 Sym->setName("___orc_rt_elfnix_tls_get_addr"); 792 } 793 794 auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO"); 795 796 if (TLSInfoEntrySection) { 797 Optional<uint64_t> Key; 798 { 799 std::lock_guard<std::mutex> Lock(MP.PlatformMutex); 800 auto I = MP.JITDylibToPThreadKey.find(&JD); 801 if (I != MP.JITDylibToPThreadKey.end()) 802 Key = I->second; 803 } 804 if (!Key) { 805 if (auto KeyOrErr = MP.createPThreadKey()) 806 Key = *KeyOrErr; 807 else 808 return KeyOrErr.takeError(); 809 } 810 811 uint64_t PlatformKeyBits = 812 support::endian::byte_swap(*Key, G.getEndianness()); 813 814 for (auto *B : TLSInfoEntrySection->blocks()) { 815 // FIXME: The TLS descriptor byte length may different with different 816 // ISA 817 assert(B->getSize() == (G.getPointerSize() * 2) && 818 "TLS descriptor must be 2 words length"); 819 auto TLSInfoEntryContent = B->getMutableContent(G); 820 memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize()); 821 } 822 } 823 824 return Error::success(); 825 } 826 827 } // End namespace orc. 828 } // End namespace llvm. 829