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