LLVM 24.0.0git
ELFNixPlatform.cpp
Go to the documentation of this file.
1//===----- ELFNixPlatform.cpp - Utilities for executing ELFNix 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
11
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/Endian.h"
26#include <optional>
27
28#define DEBUG_TYPE "orc"
29
30using namespace llvm;
31using namespace llvm::orc;
32using namespace llvm::orc::shared;
33
34// Controller-interface descriptors for the ELFNix platform runtime's SPS
35// wrapper calls.
38 static constexpr SymbolNameSpec Name =
39 SymbolNameSpec::c("__orc_rt_elfnix_create_pthread_key");
41};
42} // namespace llvm::orc::elfnix_sps_ci
43
44// Specs for the call-controller handlers that the ELFNix platform
45// runtime calls.
48 : sps::HandlerSpec<SPSExpected<SPSELFNixJITDylibDepInfoMap>(
49 SPSExecutorAddr)> {
50 static constexpr SymbolNameSpec Name =
51 SymbolNameSpec::c("__orc_rt_elfnix_push_initializers_tag");
52};
53struct LookupSymbol : sps::HandlerSpec<SPSExpected<SPSExecutorAddr>(
54 SPSExecutorAddr, SPSString)> {
55 static constexpr SymbolNameSpec Name =
56 SymbolNameSpec::c("__orc_rt_elfnix_symbol_lookup_tag");
57};
58} // namespace llvm::orc::elfnix_sps_handlers
59
60namespace {
61
62template <typename SPSSerializer, typename... ArgTs>
64getArgDataBufferType(const ArgTs &...Args) {
66 ArgData.resize(SPSSerializer::size(Args...));
67 SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
68 ArgData.size());
69 if (SPSSerializer::serialize(OB, Args...))
70 return ArgData;
71 return {};
72}
73
74std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(ELFNixPlatform &MOP,
75 std::string Name) {
76 auto &ES = MOP.getExecutionSession();
77 return std::make_unique<jitlink::LinkGraph>(
78 std::move(Name), ES.getSymbolStringPool(), ES.getTargetTriple(),
79 ES.getTargetTriple().getArchPointerBitWidth() / 8, SubtargetFeatures(),
81}
82
83// Creates a Bootstrap-Complete LinkGraph to run deferred actions.
84class ELFNixPlatformCompleteBootstrapMaterializationUnit
85 : public MaterializationUnit {
86public:
87 ELFNixPlatformCompleteBootstrapMaterializationUnit(
88 ELFNixPlatform &MOP, StringRef PlatformJDName,
89 SymbolStringPtr CompleteBootstrapSymbol, DeferredRuntimeFnMap DeferredAAs,
90 ExecutorAddr ELFNixHeaderAddr, ExecutorAddr PlatformBootstrap,
91 ExecutorAddr PlatformShutdown, ExecutorAddr RegisterJITDylib,
92 ExecutorAddr DeregisterJITDylib)
93 : MaterializationUnit(
94 {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
95 MOP(MOP), PlatformJDName(PlatformJDName),
96 CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
97 DeferredAAsMap(std::move(DeferredAAs)),
98 ELFNixHeaderAddr(ELFNixHeaderAddr),
99 PlatformBootstrap(PlatformBootstrap),
100 PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
101 DeregisterJITDylib(DeregisterJITDylib) {}
102
103 StringRef getName() const override {
104 return "ELFNixPlatformCompleteBootstrap";
105 }
106
107 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
108 using namespace jitlink;
109 auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");
110 auto &PlaceholderSection =
111 G->createSection("__orc_rt_cplt_bs", MemProt::Read);
112 auto &PlaceholderBlock =
113 G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);
114 G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,
115 Linkage::Strong, Scope::Hidden, false, true);
116
117 // 1. Bootstrap the platform support code.
118 G->allocActions().push_back(
119 {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
120 PlatformBootstrap, ELFNixHeaderAddr)),
121 cantFail(
122 WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
123
124 // 2. Register the platform JITDylib.
125 G->allocActions().push_back(
127 SPSArgList<SPSString, SPSExecutorAddr>>(
128 RegisterJITDylib, PlatformJDName, ELFNixHeaderAddr)),
129 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
130 DeregisterJITDylib, ELFNixHeaderAddr))});
131
132 // 4. Add the deferred actions to the graph.
133 for (auto &[Fn, CallDatas] : DeferredAAsMap) {
134 for (auto &CallData : CallDatas) {
135 G->allocActions().push_back(
136 {WrapperFunctionCall(Fn.first->Addr, std::move(CallData.first)),
137 WrapperFunctionCall(Fn.second->Addr, std::move(CallData.second))});
138 }
139 }
140
141 MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
142 }
143
144 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
145
146private:
147 ELFNixPlatform &MOP;
148 StringRef PlatformJDName;
149 SymbolStringPtr CompleteBootstrapSymbol;
150 DeferredRuntimeFnMap DeferredAAsMap;
151 ExecutorAddr ELFNixHeaderAddr;
152 ExecutorAddr PlatformBootstrap;
153 ExecutorAddr PlatformShutdown;
154 ExecutorAddr RegisterJITDylib;
155 ExecutorAddr DeregisterJITDylib;
156};
157
158class DSOHandleMaterializationUnit : public MaterializationUnit {
159public:
160 DSOHandleMaterializationUnit(ELFNixPlatform &ENP,
161 const SymbolStringPtr &DSOHandleSymbol)
162 : MaterializationUnit(
163 createDSOHandleSectionInterface(ENP, DSOHandleSymbol)),
164 ENP(ENP) {}
165
166 StringRef getName() const override { return "DSOHandleMU"; }
167
168 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
169
170 auto &ES = ENP.getExecutionSession();
171
172 jitlink::Edge::Kind EdgeKind;
173 unsigned PointerSize = ES.getTargetTriple().getArchPointerBitWidth() / 8;
174
175 switch (ES.getTargetTriple().getArch()) {
176 case Triple::x86_64:
178 break;
179 case Triple::aarch64:
181 break;
182 case Triple::ppc64:
183 EdgeKind = jitlink::ppc64::Pointer64;
184 break;
185 case Triple::ppc64le:
186 EdgeKind = jitlink::ppc64::Pointer64;
187 break;
190 break;
191 case Triple::mips:
192 case Triple::mipsel:
193 EdgeKind = jitlink::mips::Pointer32;
194 break;
195 case Triple::mips64:
196 case Triple::mips64el:
197 if (ES.getTargetTriple().isABIN32()) {
198 EdgeKind = jitlink::mips::Pointer32;
199 PointerSize = 4;
200 } else
201 EdgeKind = jitlink::mips::Pointer64;
202 break;
203 case Triple::systemz:
205 break;
206 default:
207 llvm_unreachable("Unrecognized architecture");
208 }
209
210 // void *__dso_handle = &__dso_handle;
211 auto G = std::make_unique<jitlink::LinkGraph>(
212 "<DSOHandleMU>", ES.getSymbolStringPool(), ES.getTargetTriple(),
213 PointerSize, SubtargetFeatures(), jitlink::getGenericEdgeKindName);
214 auto &DSOHandleSection =
215 G->createSection(".data.__dso_handle", MemProt::Read);
216 auto &DSOHandleBlock = G->createContentBlock(
217 DSOHandleSection, getDSOHandleContent(G->getPointerSize()),
218 orc::ExecutorAddr(), 8, 0);
219 auto &DSOHandleSymbol = G->addDefinedSymbol(
220 DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(),
221 jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
222 DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0);
223
224 ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
225 }
226
227 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
228
229private:
230 static MaterializationUnit::Interface
231 createDSOHandleSectionInterface(ELFNixPlatform &ENP,
232 const SymbolStringPtr &DSOHandleSymbol) {
234 SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported;
235 return MaterializationUnit::Interface(std::move(SymbolFlags),
236 DSOHandleSymbol);
237 }
238
239 ArrayRef<char> getDSOHandleContent(size_t PointerSize) {
240 static const char Content[8] = {0};
241 assert(PointerSize <= sizeof Content);
242 return {Content, PointerSize};
243 }
244
245 ELFNixPlatform &ENP;
246};
247
248} // end anonymous namespace
249
250namespace llvm {
251namespace orc {
252
253Expected<std::unique_ptr<ELFNixPlatform>>
255 JITDylib &PlatformJD,
256 std::unique_ptr<DefinitionGenerator> OrcRuntime,
257 std::optional<SymbolAliasMap> RuntimeAliases) {
258
259 auto &ES = ObjLinkingLayer.getExecutionSession();
260
261 // If the target is not supported then bail out immediately.
262 if (!supportedTarget(ES.getTargetTriple()))
263 return make_error<StringError>("Unsupported ELFNixPlatform triple: " +
264 ES.getTargetTriple().str(),
266
267 // Create default aliases if the caller didn't supply any.
268 if (!RuntimeAliases) {
269 auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD);
270 if (!StandardRuntimeAliases)
271 return StandardRuntimeAliases.takeError();
272 RuntimeAliases = std::move(*StandardRuntimeAliases);
273 }
274
275 // Define the aliases.
276 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
277 return std::move(Err);
278
279 {
280 // Add JIT dispatch reexports from bootstrap JITDylib.
281 MangleAndInterner Mangle(ES);
282 auto Exports = buildSimpleReexportsAliasMap(
283 ES.getBootstrapJITDylib(),
284 {{Mangle(rt::DispatchName), Mangle(rt::DispatchCtxName)}});
285 if (!Exports)
286 return Exports.takeError();
287 if (auto Err =
288 PlatformJD.define(reexports(ES.getBootstrapJITDylib(), *Exports)))
289 return Err;
290 }
291
292 // Create the instance.
293 Error Err = Error::success();
294 auto P = std::unique_ptr<ELFNixPlatform>(new ELFNixPlatform(
295 ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));
296 if (Err)
297 return std::move(Err);
298 return std::move(P);
299}
300
303 JITDylib &PlatformJD, const char *OrcRuntimePath,
304 std::optional<SymbolAliasMap> RuntimeAliases) {
305
306 // Create a generator for the ORC runtime archive.
307 auto OrcRuntimeArchiveGenerator =
308 StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
309 if (!OrcRuntimeArchiveGenerator)
310 return OrcRuntimeArchiveGenerator.takeError();
311
312 return Create(ObjLinkingLayer, PlatformJD,
313 std::move(*OrcRuntimeArchiveGenerator),
314 std::move(RuntimeAliases));
315}
316
318 if (auto Err = JD.define(std::make_unique<DSOHandleMaterializationUnit>(
319 *this, DSOHandleSymbol)))
320 return Err;
321
322 return ES.lookup({&JD}, DSOHandleSymbol).takeError();
323}
324
326 std::lock_guard<std::mutex> Lock(PlatformMutex);
327 auto I = JITDylibToHandleAddr.find(&JD);
328 if (I != JITDylibToHandleAddr.end()) {
329 assert(HandleAddrToJITDylib.count(I->second) &&
330 "HandleAddrToJITDylib missing entry");
331 HandleAddrToJITDylib.erase(I->second);
332 JITDylibToHandleAddr.erase(I);
333 }
334 return Error::success();
335}
336
338 const MaterializationUnit &MU) {
339
340 auto &JD = RT.getJITDylib();
341 const auto &InitSym = MU.getInitializerSymbol();
342 if (!InitSym)
343 return Error::success();
344
345 RegisteredInitSymbols[&JD].add(InitSym,
347 LLVM_DEBUG({
348 dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym
349 << " for MU " << MU.getName() << "\n";
350 });
351 return Error::success();
352}
353
357
359 ArrayRef<std::pair<const char *, const char *>> AL) {
360 for (auto &KV : AL) {
361 auto AliasName = ES.intern(KV.first);
362 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
363 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
365 }
366}
367
370 JITDylib &PlatformJD) {
371 SymbolAliasMap Aliases;
372 addAliases(ES, Aliases, requiredCXXAliases());
375 return Aliases;
376}
377
380 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
381 {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"},
382 {"atexit", "__orc_rt_elfnix_atexit"}};
383
384 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
385}
386
389 static const std::pair<const char *, const char *>
390 StandardRuntimeUtilityAliases[] = {
391 {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},
392 {"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"},
393 {"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"},
394 {"__orc_rt_jit_dlupdate", "__orc_rt_elfnix_jit_dlupdate"},
395 {"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"},
396 {"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"},
397 {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
398
400 StandardRuntimeUtilityAliases);
401}
402
405 static const std::pair<const char *, const char *>
406 StandardLazyCompilationAliases[] = {
407 {"__orc_rt_reenter", "__orc_rt_sysv_reenter"}};
408
410 StandardLazyCompilationAliases);
411}
412
413bool ELFNixPlatform::supportedTarget(const Triple &TT) {
414 switch (TT.getArch()) {
415 case Triple::x86_64:
416 case Triple::aarch64:
417 // FIXME: jitlink for ppc64 hasn't been well tested, leave it unsupported
418 // right now.
419 case Triple::ppc64le:
421 case Triple::systemz:
422 case Triple::mips:
423 case Triple::mipsel:
424 case Triple::mips64:
425 case Triple::mips64el:
426 return true;
427 default:
428 return false;
429 }
430}
431
432ELFNixPlatform::ELFNixPlatform(
433 ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
434 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
435 : ES(ObjLinkingLayer.getExecutionSession()), PlatformJD(PlatformJD),
436 ObjLinkingLayer(ObjLinkingLayer),
437 DSOHandleSymbol(ES.intern("__dso_handle")) {
439 ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));
440
441 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
442
443 BootstrapInfo BI;
444 Bootstrap = &BI;
445
446 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
447 // the platform now), so set it up.
448 if (auto E2 = setupJITDylib(PlatformJD)) {
449 Err = std::move(E2);
450 return;
451 }
452
453 // Step (2) Request runtime registration functions to trigger
454 // materialization..
455 if ((Err = ES.lookup(
456 makeJITDylibSearchOrder(&PlatformJD),
457 SymbolLookupSet(
458 {PlatformBootstrap.Name, PlatformShutdown.Name,
459 RegisterJITDylib.Name, DeregisterJITDylib.Name,
460 RegisterInitSections.Name, DeregisterInitSections.Name,
461 RegisterFiniSections.Name, DeregisterFiniSections.Name,
462 RegisterObjectSections.Name,
463 DeregisterObjectSections.Name, CreatePThreadKey.Name}))
464 .takeError()))
465 return;
466
467 // Step (3) Wait for any incidental linker work to complete.
468 {
469 std::unique_lock<std::mutex> Lock(BI.Mutex);
470 BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
471 Bootstrap = nullptr;
472 }
473
474 // Step (4) Add complete-bootstrap materialization unit and request.
475 auto BootstrapCompleteSymbol =
476 ES.intern("__orc_rt_elfnix_complete_bootstrap");
477 if ((Err = PlatformJD.define(
478 std::make_unique<ELFNixPlatformCompleteBootstrapMaterializationUnit>(
479 *this, PlatformJD.getName(), BootstrapCompleteSymbol,
480 std::move(BI.DeferredRTFnMap), BI.ELFNixHeaderAddr,
481 PlatformBootstrap.Addr, PlatformShutdown.Addr,
482 RegisterJITDylib.Addr, DeregisterJITDylib.Addr))))
483 return;
484 if ((Err = ES.lookup(makeJITDylibSearchOrder(
486 std::move(BootstrapCompleteSymbol))
487 .takeError()))
488 return;
489
490 // Associate wrapper function tags with JIT-side function implementations.
491 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
492 Err = std::move(E2);
493 return;
494 }
495}
496
497Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
498 return ES.registerCallControllerHandlers(
499 PlatformJD,
501 this, &ELFNixPlatform::rt_recordInitializers),
503 this, &ELFNixPlatform::rt_lookupSymbol));
504}
505
506void ELFNixPlatform::pushInitializersLoop(
507 PushInitializersSendResultFn SendResult, JITDylibSP JD) {
508 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
509 DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
510 SmallVector<JITDylib *, 16> Worklist({JD.get()});
511
512 ES.runSessionLocked([&]() {
513 while (!Worklist.empty()) {
514 // FIXME: Check for defunct dylibs.
515
516 auto DepJD = Worklist.back();
517 Worklist.pop_back();
518
519 // If we've already visited this JITDylib on this iteration then continue.
520 auto [It, Inserted] = JDDepMap.try_emplace(DepJD);
521 if (!Inserted)
522 continue;
523
524 // Add dep info.
525 auto &DM = It->second;
526 DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
527 for (auto &KV : O) {
528 if (KV.first == DepJD)
529 continue;
530 DM.push_back(KV.first);
531 Worklist.push_back(KV.first);
532 }
533 });
534
535 // Add any registered init symbols.
536 auto RISItr = RegisteredInitSymbols.find(DepJD);
537 if (RISItr != RegisteredInitSymbols.end()) {
538 NewInitSymbols[DepJD] = std::move(RISItr->second);
539 RegisteredInitSymbols.erase(RISItr);
540 }
541 }
542 });
543
544 // If there are no further init symbols to look up then send the link order
545 // (as a list of header addresses) to the caller.
546 if (NewInitSymbols.empty()) {
547
548 // To make the list intelligible to the runtime we need to convert all
549 // JITDylib pointers to their header addresses. Only include JITDylibs
550 // that appear in the JITDylibToHandleAddr map (i.e. those that have been
551 // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
552 DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
553 HeaderAddrs.reserve(JDDepMap.size());
554 {
555 std::lock_guard<std::mutex> Lock(PlatformMutex);
556 for (auto &KV : JDDepMap) {
557 auto I = JITDylibToHandleAddr.find(KV.first);
558 if (I != JITDylibToHandleAddr.end())
559 HeaderAddrs[KV.first] = I->second;
560 }
561 }
562
563 // Build the dep info map to return.
565 DIM.reserve(JDDepMap.size());
566 for (auto &KV : JDDepMap) {
567 auto HI = HeaderAddrs.find(KV.first);
568 // Skip unmanaged JITDylibs.
569 if (HI == HeaderAddrs.end())
570 continue;
571 auto H = HI->second;
572 ELFNixJITDylibDepInfo DepInfo;
573 for (auto &Dep : KV.second) {
574 auto HJ = HeaderAddrs.find(Dep);
575 if (HJ != HeaderAddrs.end())
576 DepInfo.push_back(HJ->second);
577 }
578 DIM.push_back(std::make_pair(H, std::move(DepInfo)));
579 }
580 SendResult(DIM);
581 return;
582 }
583
584 // Otherwise issue a lookup and re-run this phase when it completes.
586 [this, SendResult = std::move(SendResult), JD](Error Err) mutable {
587 if (Err)
588 SendResult(std::move(Err));
589 else
590 pushInitializersLoop(std::move(SendResult), JD);
591 },
592 ES, std::move(NewInitSymbols));
593}
594
595void ELFNixPlatform::rt_recordInitializers(
596 PushInitializersSendResultFn SendResult, ExecutorAddr JDHeaderAddr) {
597 JITDylibSP JD;
598 {
599 std::lock_guard<std::mutex> Lock(PlatformMutex);
600 auto I = HandleAddrToJITDylib.find(JDHeaderAddr);
601 if (I != HandleAddrToJITDylib.end())
602 JD = I->second;
603 }
604
605 LLVM_DEBUG({
606 dbgs() << "ELFNixPlatform::rt_recordInitializers(" << JDHeaderAddr << ") ";
607 if (JD)
608 dbgs() << "pushing initializers for " << JD->getName() << "\n";
609 else
610 dbgs() << "No JITDylib for header address.\n";
611 });
612
613 if (!JD) {
614 SendResult(make_error<StringError>("No JITDylib with header addr " +
615 formatv("{0:x}", JDHeaderAddr),
617 return;
618 }
619
620 pushInitializersLoop(std::move(SendResult), JD);
621}
622
623void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
624 ExecutorAddr Handle,
625 StringRef SymbolName) {
626 LLVM_DEBUG({
627 dbgs() << "ELFNixPlatform::rt_lookupSymbol(\"" << Handle << "\")\n";
628 });
629
630 JITDylib *JD = nullptr;
631
632 {
633 std::lock_guard<std::mutex> Lock(PlatformMutex);
634 auto I = HandleAddrToJITDylib.find(Handle);
635 if (I != HandleAddrToJITDylib.end())
636 JD = I->second;
637 }
638
639 if (!JD) {
640 LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle << "\n");
641 SendResult(make_error<StringError>("No JITDylib associated with handle " +
642 formatv("{0:x}", Handle),
644 return;
645 }
646
647 // Use functor class to work around XL build compiler issue on AIX.
648 class RtLookupNotifyComplete {
649 public:
650 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
651 : SendResult(std::move(SendResult)) {}
652 void operator()(Expected<SymbolMap> Result) {
653 if (Result) {
654 assert(Result->size() == 1 && "Unexpected result map count");
655 SendResult(Result->begin()->second.getAddress());
656 } else {
657 SendResult(Result.takeError());
658 }
659 }
660
661 private:
662 SendSymbolAddressFn SendResult;
663 };
664
665 ES.lookup(
667 SymbolLookupSet(ES.intern(SymbolName)), SymbolState::Ready,
668 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
669}
670
671Error ELFNixPlatform::ELFNixPlatformPlugin::bootstrapPipelineStart(
672 jitlink::LinkGraph &G) {
673 // Increment the active graphs count in BootstrapInfo.
674 std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
675 ++MP.Bootstrap.load()->ActiveGraphs;
676 return Error::success();
677}
678
679Error ELFNixPlatform::ELFNixPlatformPlugin::
680 bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {
681 // Record bootstrap function names.
682 std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {
683 {*MP.DSOHandleSymbol, &MP.Bootstrap.load()->ELFNixHeaderAddr},
684 {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},
685 {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},
686 {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},
687 {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},
688 {*MP.RegisterObjectSections.Name, &MP.RegisterObjectSections.Addr},
689 {*MP.DeregisterObjectSections.Name, &MP.DeregisterObjectSections.Addr},
690 {*MP.RegisterInitSections.Name, &MP.RegisterInitSections.Addr},
691 {*MP.DeregisterInitSections.Name, &MP.DeregisterInitSections.Addr},
692 {*MP.RegisterFiniSections.Name, &MP.RegisterFiniSections.Addr},
693 {*MP.DeregisterFiniSections.Name, &MP.DeregisterFiniSections.Addr},
694 {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}};
695
696 bool RegisterELFNixHeader = false;
697
698 for (auto *Sym : G.defined_symbols()) {
699 for (auto &RTSym : RuntimeSymbols) {
700 if (Sym->hasName() && *Sym->getName() == RTSym.first) {
701 if (*RTSym.second)
703 "Duplicate " + RTSym.first +
704 " detected during ELFNixPlatform bootstrap",
706
707 if (*Sym->getName() == *MP.DSOHandleSymbol)
708 RegisterELFNixHeader = true;
709
710 *RTSym.second = Sym->getAddress();
711 }
712 }
713 }
714
715 if (RegisterELFNixHeader) {
716 // If this graph defines the elfnix header symbol then create the internal
717 // mapping between it and PlatformJD.
718 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
719 MP.JITDylibToHandleAddr[&MP.PlatformJD] =
720 MP.Bootstrap.load()->ELFNixHeaderAddr;
721 MP.HandleAddrToJITDylib[MP.Bootstrap.load()->ELFNixHeaderAddr] =
722 &MP.PlatformJD;
723 }
724
725 return Error::success();
726}
727
728Error ELFNixPlatform::ELFNixPlatformPlugin::bootstrapPipelineEnd(
729 jitlink::LinkGraph &G) {
730 std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
731 assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed");
732 --MP.Bootstrap.load()->ActiveGraphs;
733 // Notify Bootstrap->CV while holding the mutex because the mutex is
734 // also keeping Bootstrap->CV alive.
735 if (MP.Bootstrap.load()->ActiveGraphs == 0)
736 MP.Bootstrap.load()->CV.notify_all();
737 return Error::success();
738}
739
740Error ELFNixPlatform::registerPerObjectSections(
741 jitlink::LinkGraph &G, const ELFPerObjectSectionsToRegister &POSR,
742 bool IsBootstrapping) {
743 using SPSRegisterPerObjSectionsArgs =
744 SPSArgList<SPSELFPerObjectSectionsToRegister>;
745
746 if (LLVM_UNLIKELY(IsBootstrapping)) {
747 Bootstrap.load()->addArgumentsToRTFnMap(
748 &RegisterObjectSections, &DeregisterObjectSections,
749 getArgDataBufferType<SPSRegisterPerObjSectionsArgs>(POSR),
750 getArgDataBufferType<SPSRegisterPerObjSectionsArgs>(POSR));
751 return Error::success();
752 }
753
754 G.allocActions().push_back(
756 RegisterObjectSections.Addr, POSR)),
758 DeregisterObjectSections.Addr, POSR))});
759
760 return Error::success();
761}
762
763Expected<uint64_t> ELFNixPlatform::createPThreadKey() {
764 if (!CreatePThreadKey.Addr)
766 "Attempting to create pthread key in target, but runtime support has "
767 "not been loaded yet",
769
770 using CreatePThreadKeyProxy = Proxy<Expected<uint64_t>()>;
771 CreatePThreadKeyProxy CreateKey(
772 sps::ProxySpec<elfnix_sps_ci::CreatePThreadKey>::dispatch,
773 CreatePThreadKey.Addr);
774 return CreateKey(ES);
775}
776
777void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig(
778 MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
779 jitlink::PassConfiguration &Config) {
780 using namespace jitlink;
781
782 bool InBootstrapPhase =
783 &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
784
785 // If we're in the bootstrap phase then increment the active graphs.
786 if (InBootstrapPhase) {
787 Config.PrePrunePasses.push_back(
788 [this](LinkGraph &G) { return bootstrapPipelineStart(G); });
789 Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
790 return bootstrapPipelineRecordRuntimeFunctions(G);
791 });
792 }
793
794 // If the initializer symbol is the __dso_handle symbol then just add
795 // the DSO handle support passes.
796 if (auto InitSymbol = MR.getInitializerSymbol()) {
797 if (InitSymbol == MP.DSOHandleSymbol && !InBootstrapPhase) {
798 addDSOHandleSupportPasses(MR, Config);
799 // The DSOHandle materialization unit doesn't require any other
800 // support, so we can bail out early.
801 return;
802 }
803
804 /// Preserve init sections.
805 Config.PrePrunePasses.push_back(
806 [this, &MR](jitlink::LinkGraph &G) -> Error {
807 if (auto Err = preserveInitSections(G, MR))
808 return Err;
809 return Error::success();
810 });
811 }
812
813 // Add passes for eh-frame and TLV support.
814 addEHAndTLVSupportPasses(MR, Config, InBootstrapPhase);
815
816 // If the object contains initializers then add passes to record them.
817 Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib(),
818 InBootstrapPhase](jitlink::LinkGraph &G) {
819 return registerInitSections(G, JD, InBootstrapPhase);
820 });
821
822 // If the object contains finalizers then add passes to record them.
823 Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib(),
824 InBootstrapPhase](jitlink::LinkGraph &G) {
825 return registerFiniSections(G, JD, InBootstrapPhase);
826 });
827
828 // If we're in the bootstrap phase then steal allocation actions and then
829 // decrement the active graphs.
830 if (InBootstrapPhase)
831 Config.PostFixupPasses.push_back(
832 [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });
833}
834
835void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses(
836 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
837
838 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](
839 jitlink::LinkGraph &G) -> Error {
840 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
841 return Sym->getName() == MP.DSOHandleSymbol;
842 });
843 assert(I != G.defined_symbols().end() && "Missing DSO handle symbol");
844 {
845 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
846 auto HandleAddr = (*I)->getAddress();
847 MP.HandleAddrToJITDylib[HandleAddr] = &JD;
848 MP.JITDylibToHandleAddr[&JD] = HandleAddr;
849
850 G.allocActions().push_back(
852 SPSArgList<SPSString, SPSExecutorAddr>>(
853 MP.RegisterJITDylib.Addr, JD.getName(), HandleAddr)),
854 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
855 MP.DeregisterJITDylib.Addr, HandleAddr))});
856 }
857 return Error::success();
858 });
859}
860
861void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses(
862 MaterializationResponsibility &MR, jitlink::PassConfiguration &Config,
863 bool IsBootstrapping) {
864
865 // Insert TLV lowering at the start of the PostPrunePasses, since we want
866 // it to run before GOT/PLT lowering.
867
868 // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build
869 // pass has done. Because the TLS descriptor need to be allocate in GOT.
870 Config.PostPrunePasses.push_back(
871 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
872 return fixTLVSectionsAndEdges(G, JD);
873 });
874
875 // Add a pass to register the final addresses of the eh-frame and TLV sections
876 // with the runtime.
877 Config.PostFixupPasses.push_back([this, IsBootstrapping](
878 jitlink::LinkGraph &G) -> Error {
879 ELFPerObjectSectionsToRegister POSR;
880
881 if (auto *EHFrameSection = G.findSectionByName(ELFEHFrameSectionName)) {
882 jitlink::SectionRange R(*EHFrameSection);
883 if (!R.empty())
884 POSR.EHFrameSection = R.getRange();
885 }
886
887 // Get a pointer to the thread data section if there is one. It will be used
888 // below.
889 jitlink::Section *ThreadDataSection =
890 G.findSectionByName(ELFThreadDataSectionName);
891
892 // Handle thread BSS section if there is one.
893 if (auto *ThreadBSSSection = G.findSectionByName(ELFThreadBSSSectionName)) {
894 // If there's already a thread data section in this graph then merge the
895 // thread BSS section content into it, otherwise just treat the thread
896 // BSS section as the thread data section.
897 if (ThreadDataSection)
898 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
899 else
900 ThreadDataSection = ThreadBSSSection;
901 }
902
903 // Having merged thread BSS (if present) and thread data (if present),
904 // record the resulting section range.
905 if (ThreadDataSection) {
906 jitlink::SectionRange R(*ThreadDataSection);
907 if (!R.empty())
908 POSR.ThreadDataSection = R.getRange();
909 }
910
911 if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
912 if (auto Err = MP.registerPerObjectSections(G, POSR, IsBootstrapping))
913 return Err;
914 }
915
916 return Error::success();
917 });
918}
919
920Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
921 jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
922
923 if (const auto &InitSymName = MR.getInitializerSymbol()) {
924
925 jitlink::Symbol *InitSym = nullptr;
926
927 for (auto &InitSection : G.sections()) {
928 // Skip non-init sections.
929 if (!isELFInitializerSection(InitSection.getName()) ||
930 InitSection.empty())
931 continue;
932
933 // Create the init symbol if it has not been created already and attach it
934 // to the first block.
935 if (!InitSym) {
936 auto &B = **InitSection.blocks().begin();
937 InitSym = &G.addDefinedSymbol(
938 B, 0, *InitSymName, B.getSize(), jitlink::Linkage::Strong,
940 }
941
942 // Add keep-alive edges to anonymous symbols in all other init blocks.
943 for (auto *B : InitSection.blocks()) {
944 if (B == &InitSym->getBlock())
945 continue;
946
947 auto &S = G.addAnonymousSymbol(*B, 0, B->getSize(), false, true);
948 InitSym->getBlock().addEdge(jitlink::Edge::KeepAlive, 0, S, 0);
949 }
950 }
951
952 // Also preserve fini sections (.fini_array, .fini, .dtors)
953 for (auto &FiniSection : G.sections()) {
954 // Skip non-fini sections.
955 if (!isELFFinalizerSection(FiniSection.getName()) || FiniSection.empty())
956 continue;
957
958 // Create the init symbol if it has not been created already and attach it
959 // to the first fini block.
960 if (!InitSym) {
961 auto &B = **FiniSection.blocks().begin();
962 InitSym = &G.addDefinedSymbol(
963 B, 0, *InitSymName, B.getSize(), jitlink::Linkage::Strong,
965 }
966
967 // Add keep-alive edges to anonymous symbols in all fini blocks.
968 for (auto *B : FiniSection.blocks()) {
969 if (B == &InitSym->getBlock())
970 continue;
971
972 auto &S = G.addAnonymousSymbol(*B, 0, B->getSize(), false, true);
973 InitSym->getBlock().addEdge(jitlink::Edge::KeepAlive, 0, S, 0);
974 }
975 }
976 }
977
978 return Error::success();
979}
980
981Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections(
982 jitlink::LinkGraph &G, JITDylib &JD, bool IsBootstrapping) {
983 SmallVector<ExecutorAddrRange> ELFNixPlatformSecs;
984 LLVM_DEBUG(dbgs() << "ELFNixPlatform::registerInitSections\n");
985
986 SmallVector<jitlink::Section *> OrderedInitSections;
987 for (auto &Sec : G.sections())
988 if (isELFInitializerSection(Sec.getName()))
989 OrderedInitSections.push_back(&Sec);
990
991 // Helper to get section type and priority for sorting.
992 // Returns: {type_order, priority, has_priority}
993 // type_order: 0 = .init_array, 1 = .init, 2 = .ctors
994 auto getInitSectionInfo =
995 [](const jitlink::Section *Sec) -> std::tuple<int, uint64_t, bool> {
996 StringRef Name = Sec->getName();
997 if (Name.starts_with(".init_array")) {
998 StringRef PrioStr = Name;
999 uint64_t Prio = 0;
1000 bool HasPrio = PrioStr.consume_front(".init_array.") &&
1001 !PrioStr.getAsInteger(10, Prio);
1002 return {0, Prio, HasPrio};
1003 }
1004 if (Name.starts_with(".init"))
1005 return {1, 0, false};
1006 if (Name.starts_with(".ctors")) {
1007 StringRef PrioStr = Name;
1008 uint64_t Prio = 0;
1009 bool HasPrio =
1010 PrioStr.consume_front(".ctors.") && !PrioStr.getAsInteger(10, Prio);
1011 return {2, Prio, HasPrio};
1012 }
1013 return {3, 0, false};
1014 };
1015
1016 // Sort init sections:
1017 // 1. .init_array sections first (ascending priority - lower runs first)
1018 // 2. .init sections next
1019 // 3. .ctors sections last (descending priority - higher runs first, legacy
1020 // behavior)
1021 llvm::sort(OrderedInitSections,
1022 [&](const jitlink::Section *LHS, const jitlink::Section *RHS) {
1023 auto [LType, LPrio, LHasPrio] = getInitSectionInfo(LHS);
1024 auto [RType, RPrio, RHasPrio] = getInitSectionInfo(RHS);
1025
1026 if (LType != RType)
1027 return LType < RType;
1028
1029 // Same type - sort by priority
1030 if (LType == 0) {
1031 // .init_array: ascending priority (lower priority number runs
1032 // first)
1033 if (LHasPrio && RHasPrio)
1034 return LPrio < RPrio;
1035 if (LHasPrio)
1036 return true;
1037 if (RHasPrio)
1038 return false;
1039 } else if (LType == 2) {
1040 // .ctors: descending priority (higher priority number runs
1041 // first)
1042 if (LHasPrio && RHasPrio)
1043 return LPrio > RPrio;
1044 if (LHasPrio)
1045 return true;
1046 if (RHasPrio)
1047 return false;
1048 }
1049 return LHS->getName() < RHS->getName();
1050 });
1051
1052 for (auto &Sec : OrderedInitSections)
1053 ELFNixPlatformSecs.push_back(jitlink::SectionRange(*Sec).getRange());
1054
1055 // Dump the scraped inits.
1056 LLVM_DEBUG({
1057 dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n";
1058 for (auto &Sec : G.sections()) {
1059 jitlink::SectionRange R(Sec);
1060 dbgs() << " " << Sec.getName() << ": " << R.getRange() << "\n";
1061 }
1062 });
1063
1064 ExecutorAddr HeaderAddr;
1065 {
1066 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1067 auto I = MP.JITDylibToHandleAddr.find(&JD);
1068 assert(I != MP.JITDylibToHandleAddr.end() && "No header registered for JD");
1069 assert(I->second && "Null header registered for JD");
1070 HeaderAddr = I->second;
1071 }
1072
1073 using SPSRegisterInitSectionsArgs =
1074 SPSArgList<SPSExecutorAddr, SPSSequence<SPSExecutorAddrRange>>;
1075
1076 if (LLVM_UNLIKELY(IsBootstrapping)) {
1077 MP.Bootstrap.load()->addArgumentsToRTFnMap(
1078 &MP.RegisterInitSections, &MP.DeregisterInitSections,
1079 getArgDataBufferType<SPSRegisterInitSectionsArgs>(HeaderAddr,
1080 ELFNixPlatformSecs),
1081 getArgDataBufferType<SPSRegisterInitSectionsArgs>(HeaderAddr,
1082 ELFNixPlatformSecs));
1083 return Error::success();
1084 }
1085
1086 G.allocActions().push_back(
1088 MP.RegisterInitSections.Addr, HeaderAddr, ELFNixPlatformSecs)),
1090 MP.DeregisterInitSections.Addr, HeaderAddr, ELFNixPlatformSecs))});
1091
1092 return Error::success();
1093}
1094
1095Error ELFNixPlatform::ELFNixPlatformPlugin::registerFiniSections(
1096 jitlink::LinkGraph &G, JITDylib &JD, bool IsBootstrapping) {
1097 SmallVector<ExecutorAddrRange> ELFNixFiniSecs;
1098 LLVM_DEBUG(dbgs() << "ELFNixPlatform::registerFiniSections\n");
1099
1100 SmallVector<jitlink::Section *> OrderedFiniSections;
1101 for (auto &Sec : G.sections())
1102 if (isELFFinalizerSection(Sec.getName()))
1103 OrderedFiniSections.push_back(&Sec);
1104
1105 // Helper to get section type and priority for sorting.
1106 // Returns: {type_order, priority, has_priority}
1107 // type_order: 0 = .dtors, 1 = .fini, 2 = .fini_array
1108 auto getFiniSectionInfo =
1109 [](const jitlink::Section *Sec) -> std::tuple<int, uint64_t, bool> {
1110 StringRef Name = Sec->getName();
1111 if (Name.starts_with(".dtors")) {
1112 StringRef PrioStr = Name;
1113 uint64_t Prio = 0;
1114 bool HasPrio =
1115 PrioStr.consume_front(".dtors.") && !PrioStr.getAsInteger(10, Prio);
1116 return {0, Prio, HasPrio};
1117 }
1118 if (Name.starts_with(".fini"))
1119 if (!Name.starts_with(".fini_array"))
1120 return {1, 0, false};
1121 if (Name.starts_with(".fini_array")) {
1122 StringRef PrioStr = Name;
1123 uint64_t Prio = 0;
1124 bool HasPrio = PrioStr.consume_front(".fini_array.") &&
1125 !PrioStr.getAsInteger(10, Prio);
1126 return {2, Prio, HasPrio};
1127 }
1128 return {3, 0, false};
1129 };
1130
1131 // Sort fini sections:
1132 // 1. .dtors sections first (ascending priority, as they appear)
1133 // 2. .fini sections next
1134 // 3. .fini_array sections last (descending priority - higher runs first)
1135 llvm::sort(OrderedFiniSections,
1136 [&](const jitlink::Section *LHS, const jitlink::Section *RHS) {
1137 auto [LType, LPrio, LHasPrio] = getFiniSectionInfo(LHS);
1138 auto [RType, RPrio, RHasPrio] = getFiniSectionInfo(RHS);
1139
1140 if (LType != RType)
1141 return LType < RType;
1142
1143 // Same type - sort by priority
1144 if (LType == 0) {
1145 // .dtors: no-priority first, then ascending priority (lower
1146 // runs first)
1147 if (LHasPrio && RHasPrio)
1148 return LPrio < RPrio;
1149 if (LHasPrio)
1150 return false;
1151 if (RHasPrio)
1152 return true;
1153 } else if (LType == 2) {
1154 // .fini_array: no-priority first, then descending priority
1155 // (higher runs first)
1156 if (LHasPrio && RHasPrio)
1157 return LPrio > RPrio;
1158 if (LHasPrio)
1159 return false;
1160 if (RHasPrio)
1161 return true;
1162 }
1163 return LHS->getName() < RHS->getName();
1164 });
1165
1166 for (auto *Sec : OrderedFiniSections)
1167 ELFNixFiniSecs.push_back(jitlink::SectionRange(*Sec).getRange());
1168
1169 if (ELFNixFiniSecs.empty())
1170 return Error::success();
1171
1172 // Dump the scraped finis.
1173 LLVM_DEBUG({
1174 dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " fini sections:\n";
1175 for (auto *Sec : OrderedFiniSections) {
1176 jitlink::SectionRange R(*Sec);
1177 dbgs() << " " << Sec->getName() << ": " << R.getRange() << "\n";
1178 }
1179 });
1180
1181 ExecutorAddr HeaderAddr;
1182 {
1183 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1184 auto I = MP.JITDylibToHandleAddr.find(&JD);
1185 assert(I != MP.JITDylibToHandleAddr.end() && "No header registered for JD");
1186 assert(I->second && "Null header registered for JD");
1187 HeaderAddr = I->second;
1188 }
1189
1190 using SPSRegisterFiniSectionsArgs =
1191 SPSArgList<SPSExecutorAddr, SPSSequence<SPSExecutorAddrRange>>;
1192
1193 if (LLVM_UNLIKELY(IsBootstrapping)) {
1194 MP.Bootstrap.load()->addArgumentsToRTFnMap(
1195 &MP.RegisterFiniSections, &MP.DeregisterFiniSections,
1196 getArgDataBufferType<SPSRegisterFiniSectionsArgs>(HeaderAddr,
1197 ELFNixFiniSecs),
1198 getArgDataBufferType<SPSRegisterFiniSectionsArgs>(HeaderAddr,
1199 ELFNixFiniSecs));
1200 return Error::success();
1201 }
1202
1203 G.allocActions().push_back(
1205 MP.RegisterFiniSections.Addr, HeaderAddr, ELFNixFiniSecs)),
1207 MP.DeregisterFiniSections.Addr, HeaderAddr, ELFNixFiniSecs))});
1208
1209 return Error::success();
1210}
1211
1212Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
1213 jitlink::LinkGraph &G, JITDylib &JD) {
1214 auto TLSGetAddrSymbolName = G.intern("__tls_get_addr");
1215 auto TLSDescResolveSymbolName = G.intern("__tlsdesc_resolver");
1216 auto TLSGetOffsetSymbolName = G.intern("__tls_get_offset");
1217 for (auto *Sym : G.external_symbols()) {
1218 if (Sym->getName() == TLSGetAddrSymbolName) {
1219 auto TLSGetAddr =
1220 MP.getExecutionSession().intern("___orc_rt_elfnix_tls_get_addr");
1221 Sym->setName(std::move(TLSGetAddr));
1222 } else if (Sym->getName() == TLSDescResolveSymbolName) {
1223 auto TLSGetAddr =
1224 MP.getExecutionSession().intern("___orc_rt_elfnix_tlsdesc_resolver");
1225 Sym->setName(std::move(TLSGetAddr));
1226 } else if (Sym->getName() == TLSGetOffsetSymbolName) {
1227 auto TLSGetAddr =
1228 MP.getExecutionSession().intern("___orc_rt_elfnix_tls_get_offset");
1229 Sym->setName(std::move(TLSGetAddr));
1230 }
1231 }
1232
1233 auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO");
1234
1235 if (TLSInfoEntrySection) {
1236 std::optional<uint64_t> Key;
1237 {
1238 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1239 auto I = MP.JITDylibToPThreadKey.find(&JD);
1240 if (I != MP.JITDylibToPThreadKey.end())
1241 Key = I->second;
1242 }
1243 if (!Key) {
1244 if (auto KeyOrErr = MP.createPThreadKey())
1245 Key = *KeyOrErr;
1246 else
1247 return KeyOrErr.takeError();
1248 }
1249
1250 for (auto *B : TLSInfoEntrySection->blocks()) {
1251 // FIXME: The TLS descriptor byte length may different with different
1252 // ISA
1253 assert(B->getSize() == (G.getPointerSize() * 2) &&
1254 "TLS descriptor must be 2 words length");
1255 auto TLSInfoEntryContent = B->getMutableContent(G);
1256 if (G.getPointerSize() == 4)
1257 support::endian::write<uint32_t>(TLSInfoEntryContent.data(), *Key,
1258 G.getEndianness());
1259 else
1260 support::endian::write<uint64_t>(TLSInfoEntryContent.data(), *Key,
1261 G.getEndianness());
1262 }
1263 }
1264
1265 return Error::success();
1266}
1267
1268} // End namespace orc.
1269} // End namespace llvm.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:348
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
#define _
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
#define H(x, y, z)
Definition MD5.cpp:56
#define P(N)
static StringRef getName(Value *V)
#define LLVM_DEBUG(...)
Definition Debug.h:119
Value * RHS
Value * LHS
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:762
bool empty() const
Definition DenseMap.h:716
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
void reserve(size_type NumEntries)
Grow the DenseMap so that it can contain at least NumEntries items before resizing again.
Definition DenseMap.h:721
iterator end()
Definition DenseMap.h:686
unsigned size() const
Definition DenseMap.h:717
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:856
Helper for Errors used as out-parameters.
Definition Error.h:1160
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
void resize(size_type N)
void push_back(const T &Elt)
pointer data()
Return a pointer to the vector's buffer, even if empty().
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition StringRef.h:490
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition StringRef.h:661
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
@ loongarch64
Definition Triple.h:66
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:314
Mediates between ELFNix initialization and ExecutionSession state.
static Expected< SymbolAliasMap > standardPlatformAliases(ExecutionSession &ES, JITDylib &PlatformJD)
Returns an AliasMap containing the default aliases for the ELFNixPlatform.
Error notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) override
This method will be called under the ExecutionSession lock each time a MaterializationUnit is added t...
Error notifyRemoving(ResourceTracker &RT) override
This method will be called under the ExecutionSession lock when a ResourceTracker is removed.
Error setupJITDylib(JITDylib &JD) override
This method will be called outside the session lock each time a JITDylib is created (unless it is cre...
ExecutionSession & getExecutionSession() const
static ArrayRef< std::pair< const char *, const char * > > standardRuntimeUtilityAliases()
Returns the array of standard runtime utility aliases for ELF.
static Expected< std::unique_ptr< ELFNixPlatform > > Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD, std::unique_ptr< DefinitionGenerator > OrcRuntime, std::optional< SymbolAliasMap > RuntimeAliases=std::nullopt)
Try to create a ELFNixPlatform instance, adding the ORC runtime to the given JITDylib.
static ArrayRef< std::pair< const char *, const char * > > standardLazyCompilationAliases()
Returns a list of aliases required to enable lazy compilation via the ORC runtime.
static ArrayRef< std::pair< const char *, const char * > > requiredCXXAliases()
Returns the array of required CXX aliases.
Error teardownJITDylib(JITDylib &JD) override
This method will be called outside the session lock each time a JITDylib is removed to allow the Plat...
An ExecutionSession represents a running JIT program.
Definition Core.h:1097
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition Core.h:1178
Represents an address in the executor process.
Represents a JIT'd dynamic library.
Definition Core.h:668
Error define(std::unique_ptr< MaterializationUnitType > &&MU, ResourceTrackerSP RT=nullptr)
Define all symbols provided by the materialization unit to be part of this JITDylib.
Definition Core.h:1614
GeneratorT & addGenerator(std::unique_ptr< GeneratorT > DefGenerator)
Adds a definition generator to this JITDylib and returns a referenece to it.
Definition Core.h:1597
LinkGraphLinkingLayer & addPlugin(std::shared_ptr< Plugin > P)
Add a plugin.
Mangles symbol names then uniques them in the context of an ExecutionSession.
Definition Mangling.h:28
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition Core.h:343
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization pseudo-symbol, if any.
Definition Core.h:382
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
Definition Core.h:368
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
virtual StringRef getName() const =0
Return the name of this materialization unit.
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization symbol for this MaterializationUnit (if any).
An ObjectLayer implementation built on JITLink.
static void lookupInitSymbolsAsync(unique_function< void(Error)> OnComplete, ExecutionSession &ES, const DenseMap< JITDylib *, SymbolLookupSet > &InitSyms)
Performs an async lookup for the given symbols in each of the given JITDylibs, calling the given hand...
Definition Core.cpp:1489
API to remove / transfer ownership of JIT resources.
Definition Core.h:65
JITDylib & getJITDylib() const
Return the JITDylib targeted by this tracker.
Definition Core.h:80
static Expected< std::unique_ptr< StaticLibraryDefinitionGenerator > > Load(ObjectLayer &L, const char *FileName, VisitMembersFunction VisitMembers=VisitMembersFunction(), GetObjectFileInterface GetObjFileInterface=GetObjectFileInterface())
Try to create a StaticLibraryDefinitionGenerator from the given path.
A symbol name together with the naming level (SymbolNameKind) it is expressed in, so that a Mangler /...
static constexpr SymbolNameSpec c(StringRef Name)
SPS tag type for expecteds, which are either a T or a string representing an error.
Output char buffer with overflow check.
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
Base class for specs that bind handlers for calls with the SPS signature SPSSigT.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
SymbolFlags
Symbol flags.
Definition Symbol.h:25
LLVM_ABI StringRef ELFThreadBSSSectionName
JITDylibSearchOrder makeJITDylibSearchOrder(ArrayRef< JITDylib * > JDs, JITDylibLookupFlags Flags=JITDylibLookupFlags::MatchExportedSymbolsOnly)
Convenience function for creating a search order from an ArrayRef of JITDylib*, all with the same fla...
Definition Core.h:147
std::vector< std::pair< JITDylib *, JITDylibLookupFlags > > JITDylibSearchOrder
A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search order during symbol lookup.
Definition Core.h:142
IntrusiveRefCntPtr< JITDylib > JITDylibSP
Definition Core.h:60
std::vector< std::pair< ExecutorAddr, ELFNixJITDylibDepInfo > > ELFNixJITDylibDepInfoMap
std::unique_ptr< ReExportsMaterializationUnit > symbolAliases(SymbolAliasMap Aliases)
Create a ReExportsMaterializationUnit with the given aliases.
Definition Core.h:517
std::vector< ExecutorAddr > ELFNixJITDylibDepInfo
ExecutionSession::CallControllerHandlerBinding bindCallControllerHandler(HandlerT &&H, SymbolLookupFlags LF=SymbolLookupFlags::RequiredSymbol)
Bind H, using the given spec, to the tag with the spec's default name.
LLVM_ABI StringRef ELFEHFrameSectionName
std::unique_ptr< ReExportsMaterializationUnit > reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, JITDylibLookupFlags SourceJDLookupFlags=JITDylibLookupFlags::MatchExportedSymbolsOnly)
Create a materialization unit for re-exporting symbols from another JITDylib with alternative names/f...
Definition Core.h:526
static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, ArrayRef< std::pair< const char *, const char * > > AL)
DenseMap< std::pair< RuntimeFunction *, RuntimeFunction * >, SmallVector< std::pair< shared::WrapperFunctionCall::ArgDataBufferType, shared::WrapperFunctionCall::ArgDataBufferType > > > DeferredRuntimeFnMap
LLVM_ABI bool isELFFinalizerSection(StringRef SecName)
LLVM_ABI StringRef ELFThreadDataSectionName
LLVM_ABI RegisterDependenciesFunction NoDependenciesToRegister
This can be used as the value for a RegisterDependenciesFunction if there are no dependants to regist...
Definition Core.cpp:42
@ Ready
Emitted to memory, but waiting on transitive dependencies.
Definition Core.h:545
DenseMap< SymbolStringPtr, SymbolAliasMapEntry > SymbolAliasMap
A map of Symbols to (Symbol, Flags) pairs.
Definition Core.h:167
LLVM_ABI Expected< SymbolAliasMap > buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols)
Build a SymbolAliasMap for the common case where you want to re-export symbols from another JITDylib ...
Definition Core.cpp:484
LLVM_ABI bool isELFInitializerSection(StringRef SecName)
DenseMap< SymbolStringPtr, JITSymbolFlags > SymbolFlagsMap
A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:82
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition Error.h:769
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
static constexpr SymbolNameSpec Name