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