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