LLVM 17.0.0git
ELFNixPlatform.cpp
Go to the documentation of this file.
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
10
19#include "llvm/Support/Debug.h"
20#include <optional>
21
22#define DEBUG_TYPE "orc"
23
24using namespace llvm;
25using namespace llvm::orc;
26using namespace llvm::orc::shared;
27
28namespace {
29
30class DSOHandleMaterializationUnit : public MaterializationUnit {
31public:
32 DSOHandleMaterializationUnit(ELFNixPlatform &ENP,
33 const SymbolStringPtr &DSOHandleSymbol)
35 createDSOHandleSectionInterface(ENP, DSOHandleSymbol)),
36 ENP(ENP) {}
37
38 StringRef getName() const override { return "DSOHandleMU"; }
39
40 void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
41 unsigned PointerSize;
42 support::endianness Endianness;
43 jitlink::Edge::Kind EdgeKind;
44 const auto &TT = ENP.getExecutionSession().getTargetTriple();
45
46 switch (TT.getArch()) {
47 case Triple::x86_64:
48 PointerSize = 8;
49 Endianness = support::endianness::little;
51 break;
52 case Triple::aarch64:
53 PointerSize = 8;
54 Endianness = support::endianness::little;
56 break;
57 default:
58 llvm_unreachable("Unrecognized architecture");
59 }
60
61 // void *__dso_handle = &__dso_handle;
62 auto G = std::make_unique<jitlink::LinkGraph>(
63 "<DSOHandleMU>", TT, PointerSize, Endianness,
65 auto &DSOHandleSection =
66 G->createSection(".data.__dso_handle", MemProt::Read);
67 auto &DSOHandleBlock = G->createContentBlock(
68 DSOHandleSection, getDSOHandleContent(PointerSize), orc::ExecutorAddr(),
69 8, 0);
70 auto &DSOHandleSymbol = G->addDefinedSymbol(
71 DSOHandleBlock, 0, *R->getInitializerSymbol(), DSOHandleBlock.getSize(),
72 jitlink::Linkage::Strong, jitlink::Scope::Default, false, true);
73 DSOHandleBlock.addEdge(EdgeKind, 0, DSOHandleSymbol, 0);
74
75 ENP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
76 }
77
78 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
79
80private:
82 createDSOHandleSectionInterface(ELFNixPlatform &ENP,
83 const SymbolStringPtr &DSOHandleSymbol) {
85 SymbolFlags[DSOHandleSymbol] = JITSymbolFlags::Exported;
86 return MaterializationUnit::Interface(std::move(SymbolFlags),
87 DSOHandleSymbol);
88 }
89
90 ArrayRef<char> getDSOHandleContent(size_t PointerSize) {
91 static const char Content[8] = {0};
92 assert(PointerSize <= sizeof Content);
93 return {Content, PointerSize};
94 }
95
96 ELFNixPlatform &ENP;
97};
98
99} // end anonymous namespace
100
101namespace llvm {
102namespace orc {
103
105 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
106 JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
107 std::optional<SymbolAliasMap> RuntimeAliases) {
108
109 // If the target is not supported then bail out immediately.
110 if (!supportedTarget(ES.getTargetTriple()))
111 return make_error<StringError>("Unsupported ELFNixPlatform triple: " +
112 ES.getTargetTriple().str(),
114
115 auto &EPC = ES.getExecutorProcessControl();
116
117 // Create default aliases if the caller didn't supply any.
118 if (!RuntimeAliases) {
119 auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD);
120 if (!StandardRuntimeAliases)
121 return StandardRuntimeAliases.takeError();
122 RuntimeAliases = std::move(*StandardRuntimeAliases);
123 }
124
125 // Define the aliases.
126 if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
127 return std::move(Err);
128
129 // Add JIT-dispatch function support symbols.
130 if (auto Err = PlatformJD.define(absoluteSymbols(
131 {{ES.intern("__orc_rt_jit_dispatch"),
132 {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
134 {ES.intern("__orc_rt_jit_dispatch_ctx"),
135 {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
137 return std::move(Err);
138
139 // Create the instance.
140 Error Err = Error::success();
141 auto P = std::unique_ptr<ELFNixPlatform>(new ELFNixPlatform(
142 ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));
143 if (Err)
144 return std::move(Err);
145 return std::move(P);
146}
147
150 ObjectLinkingLayer &ObjLinkingLayer,
151 JITDylib &PlatformJD, const char *OrcRuntimePath,
152 std::optional<SymbolAliasMap> RuntimeAliases) {
153
154 // Create a generator for the ORC runtime archive.
155 auto OrcRuntimeArchiveGenerator =
156 StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
157 if (!OrcRuntimeArchiveGenerator)
158 return OrcRuntimeArchiveGenerator.takeError();
159
160 return Create(ES, ObjLinkingLayer, PlatformJD,
161 std::move(*OrcRuntimeArchiveGenerator),
162 std::move(RuntimeAliases));
163}
164
166 return JD.define(
167 std::make_unique<DSOHandleMaterializationUnit>(*this, DSOHandleSymbol));
168}
169
171 return Error::success();
172}
173
175 const MaterializationUnit &MU) {
176 auto &JD = RT.getJITDylib();
177 const auto &InitSym = MU.getInitializerSymbol();
178 if (!InitSym)
179 return Error::success();
180
181 RegisteredInitSymbols[&JD].add(InitSym,
183 LLVM_DEBUG({
184 dbgs() << "ELFNixPlatform: Registered init symbol " << *InitSym
185 << " for MU " << MU.getName() << "\n";
186 });
187 return Error::success();
188}
189
191 llvm_unreachable("Not supported yet");
192}
193
195 ArrayRef<std::pair<const char *, const char *>> AL) {
196 for (auto &KV : AL) {
197 auto AliasName = ES.intern(KV.first);
198 assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
199 Aliases[std::move(AliasName)] = {ES.intern(KV.second),
201 }
202}
203
206 JITDylib &PlatformJD) {
207 SymbolAliasMap Aliases;
208 addAliases(ES, Aliases, requiredCXXAliases());
210
211 // Determine whether or not the libunwind extended-API function for
212 // dynamically registering an entire .eh_frame section is available.
213 // If it is not, we assume that libgcc_s is being used, and alias to
214 // its __register_frame with the same functionality.
215 auto RTRegisterFrame = ES.intern("__orc_rt_register_eh_frame_section");
216 auto LibUnwindRegisterFrame = ES.intern("__unw_add_dynamic_eh_frame_section");
217 auto RTDeregisterFrame = ES.intern("__orc_rt_deregister_eh_frame_section");
218 auto LibUnwindDeregisterFrame =
219 ES.intern("__unw_remove_dynamic_eh_frame_section");
220 auto SM = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
222 .add(LibUnwindRegisterFrame,
224 .add(LibUnwindDeregisterFrame,
226 if (!SM) { // Weak-ref means no "missing symbol" errors, so this must be
227 // something more serious that we should report.
228 return SM.takeError();
229 } else if (SM->size() == 2) {
230 LLVM_DEBUG({
231 dbgs() << "Using libunwind " << LibUnwindRegisterFrame
232 << " for unwind info registration\n";
233 });
234 Aliases[std::move(RTRegisterFrame)] = {LibUnwindRegisterFrame,
236 Aliases[std::move(RTDeregisterFrame)] = {LibUnwindDeregisterFrame,
238 } else {
239 // Since LLVM libunwind is not present, we assume that unwinding
240 // is provided by libgcc
241 LLVM_DEBUG({
242 dbgs() << "Using libgcc __register_frame"
243 << " for unwind info registration\n";
244 });
245 Aliases[std::move(RTRegisterFrame)] = {ES.intern("__register_frame"),
247 Aliases[std::move(RTDeregisterFrame)] = {ES.intern("__deregister_frame"),
249 }
250
251 return Aliases;
252}
253
256 static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
257 {"__cxa_atexit", "__orc_rt_elfnix_cxa_atexit"},
258 {"atexit", "__orc_rt_elfnix_atexit"}};
259
260 return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
261}
262
265 static const std::pair<const char *, const char *>
266 StandardRuntimeUtilityAliases[] = {
267 {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},
268 {"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"},
269 {"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"},
270 {"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"},
271 {"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"},
272 {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
273
275 StandardRuntimeUtilityAliases);
276}
277
278bool ELFNixPlatform::supportedTarget(const Triple &TT) {
279 switch (TT.getArch()) {
280 case Triple::x86_64:
281 case Triple::aarch64:
282 return true;
283 default:
284 return false;
285 }
286}
287
288ELFNixPlatform::ELFNixPlatform(
289 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
290 JITDylib &PlatformJD,
291 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
292 : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
293 DSOHandleSymbol(ES.intern("__dso_handle")) {
295
296 ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));
297
298 PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
299
300 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
301 // the platform now), so set it up.
302 if (auto E2 = setupJITDylib(PlatformJD)) {
303 Err = std::move(E2);
304 return;
305 }
306
307 RegisteredInitSymbols[&PlatformJD].add(
309
310 // Associate wrapper function tags with JIT-side function implementations.
311 if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
312 Err = std::move(E2);
313 return;
314 }
315
316 // Lookup addresses of runtime functions callable by the platform,
317 // call the platform bootstrap function to initialize the platform-state
318 // object in the executor.
319 if (auto E2 = bootstrapELFNixRuntime(PlatformJD)) {
320 Err = std::move(E2);
321 return;
322 }
323}
324
325Error ELFNixPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
327
328 using GetInitializersSPSSig =
330 WFs[ES.intern("__orc_rt_elfnix_get_initializers_tag")] =
331 ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
332 this, &ELFNixPlatform::rt_getInitializers);
333
334 using GetDeinitializersSPSSig =
336 WFs[ES.intern("__orc_rt_elfnix_get_deinitializers_tag")] =
337 ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
338 this, &ELFNixPlatform::rt_getDeinitializers);
339
340 using LookupSymbolSPSSig =
342 WFs[ES.intern("__orc_rt_elfnix_symbol_lookup_tag")] =
343 ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
344 &ELFNixPlatform::rt_lookupSymbol);
345
346 return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
347}
348
349void ELFNixPlatform::getInitializersBuildSequencePhase(
350 SendInitializerSequenceFn SendResult, JITDylib &JD,
351 std::vector<JITDylibSP> DFSLinkOrder) {
353 {
354 std::lock_guard<std::mutex> Lock(PlatformMutex);
355 for (auto &InitJD : reverse(DFSLinkOrder)) {
356 LLVM_DEBUG({
357 dbgs() << "ELFNixPlatform: Appending inits for \"" << InitJD->getName()
358 << "\" to sequence\n";
359 });
360 auto ISItr = InitSeqs.find(InitJD.get());
361 if (ISItr != InitSeqs.end()) {
362 FullInitSeq.emplace_back(std::move(ISItr->second));
363 InitSeqs.erase(ISItr);
364 }
365 }
366 }
367
368 SendResult(std::move(FullInitSeq));
369}
370
371void ELFNixPlatform::getInitializersLookupPhase(
372 SendInitializerSequenceFn SendResult, JITDylib &JD) {
373
374 auto DFSLinkOrder = JD.getDFSLinkOrder();
375 if (!DFSLinkOrder) {
376 SendResult(DFSLinkOrder.takeError());
377 return;
378 }
379
381 ES.runSessionLocked([&]() {
382 for (auto &InitJD : *DFSLinkOrder) {
383 auto RISItr = RegisteredInitSymbols.find(InitJD.get());
384 if (RISItr != RegisteredInitSymbols.end()) {
385 NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
386 RegisteredInitSymbols.erase(RISItr);
387 }
388 }
389 });
390
391 // If there are no further init symbols to look up then move on to the next
392 // phase.
393 if (NewInitSymbols.empty()) {
394 getInitializersBuildSequencePhase(std::move(SendResult), JD,
395 std::move(*DFSLinkOrder));
396 return;
397 }
398
399 // Otherwise issue a lookup and re-run this phase when it completes.
401 [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
402 if (Err)
403 SendResult(std::move(Err));
404 else
405 getInitializersLookupPhase(std::move(SendResult), JD);
406 },
407 ES, std::move(NewInitSymbols));
408}
409
410void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
411 StringRef JDName) {
412 LLVM_DEBUG({
413 dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName << "\")\n";
414 });
415
416 JITDylib *JD = ES.getJITDylibByName(JDName);
417 if (!JD) {
418 LLVM_DEBUG({
419 dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n";
420 });
421 SendResult(make_error<StringError>("No JITDylib named " + JDName,
423 return;
424 }
425
426 getInitializersLookupPhase(std::move(SendResult), *JD);
427}
428
429void ELFNixPlatform::rt_getDeinitializers(
430 SendDeinitializerSequenceFn SendResult, ExecutorAddr Handle) {
431 LLVM_DEBUG({
432 dbgs() << "ELFNixPlatform::rt_getDeinitializers(\""
433 << formatv("{0:x}", Handle.getValue()) << "\")\n";
434 });
435
436 JITDylib *JD = nullptr;
437
438 {
439 std::lock_guard<std::mutex> Lock(PlatformMutex);
440 auto I = HandleAddrToJITDylib.find(Handle);
441 if (I != HandleAddrToJITDylib.end())
442 JD = I->second;
443 }
444
445 if (!JD) {
446 LLVM_DEBUG({
447 dbgs() << " No JITDylib for handle "
448 << formatv("{0:x}", Handle.getValue()) << "\n";
449 });
450 SendResult(make_error<StringError>("No JITDylib associated with handle " +
451 formatv("{0:x}", Handle.getValue()),
453 return;
454 }
455
457}
458
459void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
460 ExecutorAddr Handle,
461 StringRef SymbolName) {
462 LLVM_DEBUG({
463 dbgs() << "ELFNixPlatform::rt_lookupSymbol(\""
464 << formatv("{0:x}", Handle.getValue()) << "\")\n";
465 });
466
467 JITDylib *JD = nullptr;
468
469 {
470 std::lock_guard<std::mutex> Lock(PlatformMutex);
471 auto I = HandleAddrToJITDylib.find(Handle);
472 if (I != HandleAddrToJITDylib.end())
473 JD = I->second;
474 }
475
476 if (!JD) {
477 LLVM_DEBUG({
478 dbgs() << " No JITDylib for handle "
479 << formatv("{0:x}", Handle.getValue()) << "\n";
480 });
481 SendResult(make_error<StringError>("No JITDylib associated with handle " +
482 formatv("{0:x}", Handle.getValue()),
484 return;
485 }
486
487 // Use functor class to work around XL build compiler issue on AIX.
488 class RtLookupNotifyComplete {
489 public:
490 RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
491 : SendResult(std::move(SendResult)) {}
492 void operator()(Expected<SymbolMap> Result) {
493 if (Result) {
494 assert(Result->size() == 1 && "Unexpected result map count");
495 SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
496 } else {
497 SendResult(Result.takeError());
498 }
499 }
500
501 private:
502 SendSymbolAddressFn SendResult;
503 };
504
505 ES.lookup(
508 RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
509}
510
511Error ELFNixPlatform::bootstrapELFNixRuntime(JITDylib &PlatformJD) {
512
513 std::pair<const char *, ExecutorAddr *> Symbols[] = {
514 {"__orc_rt_elfnix_platform_bootstrap", &orc_rt_elfnix_platform_bootstrap},
515 {"__orc_rt_elfnix_platform_shutdown", &orc_rt_elfnix_platform_shutdown},
516 {"__orc_rt_elfnix_register_object_sections",
517 &orc_rt_elfnix_register_object_sections},
518 {"__orc_rt_elfnix_create_pthread_key",
519 &orc_rt_elfnix_create_pthread_key}};
520
521 SymbolLookupSet RuntimeSymbols;
522 std::vector<std::pair<SymbolStringPtr, ExecutorAddr *>> AddrsToRecord;
523 for (const auto &KV : Symbols) {
524 auto Name = ES.intern(KV.first);
525 RuntimeSymbols.add(Name);
526 AddrsToRecord.push_back({std::move(Name), KV.second});
527 }
528
529 auto RuntimeSymbolAddrs = ES.lookup(
530 {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols);
531 if (!RuntimeSymbolAddrs)
532 return RuntimeSymbolAddrs.takeError();
533
534 for (const auto &KV : AddrsToRecord) {
535 auto &Name = KV.first;
536 assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?");
537 KV.second->setValue((*RuntimeSymbolAddrs)[Name].getAddress());
538 }
539
540 auto PJDDSOHandle = ES.lookup(
541 {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, DSOHandleSymbol);
542 if (!PJDDSOHandle)
543 return PJDDSOHandle.takeError();
544
545 if (auto Err = ES.callSPSWrapper<void(uint64_t)>(
546 orc_rt_elfnix_platform_bootstrap, PJDDSOHandle->getAddress()))
547 return Err;
548
549 // FIXME: Ordering is fuzzy here. We're probably best off saying
550 // "behavior is undefined if code that uses the runtime is added before
551 // the platform constructor returns", then move all this to the constructor.
552 RuntimeBootstrapped = true;
553 std::vector<ELFPerObjectSectionsToRegister> DeferredPOSRs;
554 {
555 std::lock_guard<std::mutex> Lock(PlatformMutex);
556 DeferredPOSRs = std::move(BootstrapPOSRs);
557 }
558
559 for (auto &D : DeferredPOSRs)
560 if (auto Err = registerPerObjectSections(D))
561 return Err;
562
563 return Error::success();
564}
565
566Error ELFNixPlatform::registerInitInfo(
567 JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {
568
569 std::unique_lock<std::mutex> Lock(PlatformMutex);
570
571 ELFNixJITDylibInitializers *InitSeq = nullptr;
572 {
573 auto I = InitSeqs.find(&JD);
574 if (I == InitSeqs.end()) {
575 // If there's no init sequence entry yet then we need to look up the
576 // header symbol to force creation of one.
577 Lock.unlock();
578
579 auto SearchOrder =
580 JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
581 if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError())
582 return Err;
583
584 Lock.lock();
585 I = InitSeqs.find(&JD);
586 assert(I != InitSeqs.end() &&
587 "Entry missing after header symbol lookup?");
588 }
589 InitSeq = &I->second;
590 }
591
592 for (auto *Sec : InitSections) {
593 // FIXME: Avoid copy here.
595 InitSeq->InitSections[Sec->getName()].push_back(
596 {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())});
597 }
598
599 return Error::success();
600}
601
602Error ELFNixPlatform::registerPerObjectSections(
603 const ELFPerObjectSectionsToRegister &POSR) {
604
605 if (!orc_rt_elfnix_register_object_sections)
606 return make_error<StringError>("Attempting to register per-object "
607 "sections, but runtime support has not "
608 "been loaded yet",
610
611 Error ErrResult = Error::success();
612 if (auto Err = ES.callSPSWrapper<shared::SPSError(
614 orc_rt_elfnix_register_object_sections, ErrResult, POSR))
615 return Err;
616 return ErrResult;
617}
618
619Expected<uint64_t> ELFNixPlatform::createPThreadKey() {
620 if (!orc_rt_elfnix_create_pthread_key)
621 return make_error<StringError>(
622 "Attempting to create pthread key in target, but runtime support has "
623 "not been loaded yet",
625
627 if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
628 orc_rt_elfnix_create_pthread_key, Result))
629 return std::move(Err);
630 return Result;
631}
632
633void ELFNixPlatform::ELFNixPlatformPlugin::modifyPassConfig(
636
637 // If the initializer symbol is the __dso_handle symbol then just add
638 // the DSO handle support passes.
639 if (MR.getInitializerSymbol() == MP.DSOHandleSymbol) {
640 addDSOHandleSupportPasses(MR, Config);
641 // The DSOHandle materialization unit doesn't require any other
642 // support, so we can bail out early.
643 return;
644 }
645
646 // If the object contains initializers then add passes to record them.
647 if (MR.getInitializerSymbol())
648 addInitializerSupportPasses(MR, Config);
649
650 // Add passes for eh-frame and TLV support.
651 addEHAndTLVSupportPasses(MR, Config);
652}
653
655ELFNixPlatform::ELFNixPlatformPlugin::getSyntheticSymbolDependencies(
657 std::lock_guard<std::mutex> Lock(PluginMutex);
658 auto I = InitSymbolDeps.find(&MR);
659 if (I != InitSymbolDeps.end()) {
660 SyntheticSymbolDependenciesMap Result;
661 Result[MR.getInitializerSymbol()] = std::move(I->second);
662 InitSymbolDeps.erase(&MR);
663 return Result;
664 }
665 return SyntheticSymbolDependenciesMap();
666}
667
668void ELFNixPlatform::ELFNixPlatformPlugin::addInitializerSupportPasses(
670
671 /// Preserve init sections.
672 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {
673 if (auto Err = preserveInitSections(G, MR))
674 return Err;
675 return Error::success();
676 });
677
678 Config.PostFixupPasses.push_back(
679 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
680 return registerInitSections(G, JD);
681 });
682}
683
684void ELFNixPlatform::ELFNixPlatformPlugin::addDSOHandleSupportPasses(
686
687 Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](
689 auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
690 return Sym->getName() == *MP.DSOHandleSymbol;
691 });
692 assert(I != G.defined_symbols().end() && "Missing DSO handle symbol");
693 {
694 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
695 auto HandleAddr = (*I)->getAddress();
696 MP.HandleAddrToJITDylib[HandleAddr] = &JD;
697 assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists");
698 MP.InitSeqs.insert(std::make_pair(
699 &JD, ELFNixJITDylibInitializers(JD.getName(), HandleAddr)));
700 }
701 return Error::success();
702 });
703}
704
705void ELFNixPlatform::ELFNixPlatformPlugin::addEHAndTLVSupportPasses(
707
708 // Insert TLV lowering at the start of the PostPrunePasses, since we want
709 // it to run before GOT/PLT lowering.
710
711 // TODO: Check that before the fixTLVSectionsAndEdges pass, the GOT/PLT build
712 // pass has done. Because the TLS descriptor need to be allocate in GOT.
713 Config.PostPrunePasses.push_back(
714 [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
715 return fixTLVSectionsAndEdges(G, JD);
716 });
717
718 // Add a pass to register the final addresses of the eh-frame and TLV sections
719 // with the runtime.
720 Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
722
723 if (auto *EHFrameSection = G.findSectionByName(ELFEHFrameSectionName)) {
724 jitlink::SectionRange R(*EHFrameSection);
725 if (!R.empty())
726 POSR.EHFrameSection = {ExecutorAddr(R.getStart()),
727 ExecutorAddr(R.getEnd())};
728 }
729
730 // Get a pointer to the thread data section if there is one. It will be used
731 // below.
732 jitlink::Section *ThreadDataSection =
733 G.findSectionByName(ELFThreadDataSectionName);
734
735 // Handle thread BSS section if there is one.
736 if (auto *ThreadBSSSection = G.findSectionByName(ELFThreadBSSSectionName)) {
737 // If there's already a thread data section in this graph then merge the
738 // thread BSS section content into it, otherwise just treat the thread
739 // BSS section as the thread data section.
740 if (ThreadDataSection)
741 G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
742 else
743 ThreadDataSection = ThreadBSSSection;
744 }
745
746 // Having merged thread BSS (if present) and thread data (if present),
747 // record the resulting section range.
748 if (ThreadDataSection) {
749 jitlink::SectionRange R(*ThreadDataSection);
750 if (!R.empty())
751 POSR.ThreadDataSection = {ExecutorAddr(R.getStart()),
752 ExecutorAddr(R.getEnd())};
753 }
754
755 if (POSR.EHFrameSection.Start || POSR.ThreadDataSection.Start) {
756
757 // If we're still bootstrapping the runtime then just record this
758 // frame for now.
759 if (!MP.RuntimeBootstrapped) {
760 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
761 MP.BootstrapPOSRs.push_back(POSR);
762 return Error::success();
763 }
764
765 // Otherwise register it immediately.
766 if (auto Err = MP.registerPerObjectSections(POSR))
767 return Err;
768 }
769
770 return Error::success();
771 });
772}
773
774Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
776
777 JITLinkSymbolSet InitSectionSymbols;
778 for (auto &InitSection : G.sections()) {
779 // Skip non-init sections.
780 if (!isELFInitializerSection(InitSection.getName()))
781 continue;
782
783 // Make a pass over live symbols in the section: those blocks are already
784 // preserved.
785 DenseSet<jitlink::Block *> AlreadyLiveBlocks;
786 for (auto &Sym : InitSection.symbols()) {
787 auto &B = Sym->getBlock();
788 if (Sym->isLive() && Sym->getOffset() == 0 &&
789 Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
790 InitSectionSymbols.insert(Sym);
791 AlreadyLiveBlocks.insert(&B);
792 }
793 }
794
795 // Add anonymous symbols to preserve any not-already-preserved blocks.
796 for (auto *B : InitSection.blocks())
797 if (!AlreadyLiveBlocks.count(B))
798 InitSectionSymbols.insert(
799 &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
800 }
801
802 if (!InitSectionSymbols.empty()) {
803 std::lock_guard<std::mutex> Lock(PluginMutex);
804 InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
805 }
806
807 return Error::success();
808}
809
810Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections(
812
814
815 LLVM_DEBUG({ dbgs() << "ELFNixPlatform::registerInitSections\n"; });
816
817 for (auto &Sec : G.sections()) {
818 if (isELFInitializerSection(Sec.getName())) {
819 InitSections.push_back(&Sec);
820 }
821 }
822
823 // Dump the scraped inits.
824 LLVM_DEBUG({
825 dbgs() << "ELFNixPlatform: Scraped " << G.getName() << " init sections:\n";
826 for (auto *Sec : InitSections) {
828 dbgs() << " " << Sec->getName() << ": "
829 << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n";
830 }
831 });
832
833 return MP.registerInitInfo(JD, InitSections);
834}
835
836Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
838
839 for (auto *Sym : G.external_symbols()) {
840 if (Sym->getName() == "__tls_get_addr") {
841 Sym->setName("___orc_rt_elfnix_tls_get_addr");
842 } else if (Sym->getName() == "__tlsdesc_resolver") {
843 Sym->setName("___orc_rt_elfnix_tlsdesc_resolver");
844 }
845 }
846
847 auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO");
848
849 if (TLSInfoEntrySection) {
850 std::optional<uint64_t> Key;
851 {
852 std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
853 auto I = MP.JITDylibToPThreadKey.find(&JD);
854 if (I != MP.JITDylibToPThreadKey.end())
855 Key = I->second;
856 }
857 if (!Key) {
858 if (auto KeyOrErr = MP.createPThreadKey())
859 Key = *KeyOrErr;
860 else
861 return KeyOrErr.takeError();
862 }
863
864 uint64_t PlatformKeyBits =
865 support::endian::byte_swap(*Key, G.getEndianness());
866
867 for (auto *B : TLSInfoEntrySection->blocks()) {
868 // FIXME: The TLS descriptor byte length may different with different
869 // ISA
870 assert(B->getSize() == (G.getPointerSize() * 2) &&
871 "TLS descriptor must be 2 words length");
872 auto TLSInfoEntryContent = B->getMutableContent(G);
873 memcpy(TLSInfoEntryContent.data(), &PlatformKeyBits, G.getPointerSize());
874 }
875 }
876
877 return Error::success();
878}
879
880} // End namespace orc.
881} // End namespace llvm.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_DEBUG(X)
Definition: Debug.h:101
T Content
std::string Name
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
#define P(N)
if(VerifyEach)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
bool empty() const
Definition: DenseMap.h:98
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:151
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Helper for Errors used as out-parameters.
Definition: Error.h:1104
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
const std::string & str() const
Definition: Triple.h:415
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition: DenseSet.h:97
Mediates between ELFNix initialization and ExecutionSession state.
ObjectLinkingLayer & getObjectLinkingLayer() const
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(ExecutionSession &ES, 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 * > > 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:1373
ExecutorProcessControl & getExecutorProcessControl()
Get the ExecutorProcessControl object associated with this ExecutionSession.
Definition: Core.h:1416
const Triple & getTargetTriple() const
Return the triple for the executor.
Definition: Core.h:1419
Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)
Run a wrapper function using SPS to serialize the arguments and deserialize the results.
Definition: Core.h:1621
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
Definition: Core.h:1427
JITDylib * getJITDylibByName(StringRef Name)
Return a pointer to the "name" JITDylib.
Definition: Core.cpp:1939
static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H)
Wrap a handler that takes concrete argument types (and a sender for a concrete return type) to produc...
Definition: Core.h:1635
void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies)
Search the given JITDylibs for the given symbols.
Definition: Core.cpp:2084
Error registerJITDispatchHandlers(JITDylib &JD, JITDispatchHandlerAssociationMap WFs)
For each tag symbol name, associate the corresponding AsyncHandlerWrapperFunction with the address of...
Definition: Core.cpp:2193
decltype(auto) runSessionLocked(Func &&F)
Run the given lambda with the session mutex locked.
Definition: Core.h:1437
Represents an address in the executor process.
uint64_t getValue() const
Represents a JIT'd dynamic library.
Definition: Core.h:962
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:1816
static Expected< std::vector< JITDylibSP > > getDFSLinkOrder(ArrayRef< JITDylibSP > JDs)
Returns the given JITDylibs and all of their transitive dependencies in DFS order (based on linkage r...
Definition: Core.cpp:2004
auto withLinkOrderDo(Func &&F) -> decltype(F(std::declval< const JITDylibSearchOrder & >()))
Do something with the link order (run under the session lock).
Definition: Core.h:1809
GeneratorT & addGenerator(std::unique_ptr< GeneratorT > DefGenerator)
Adds a definition generator to this JITDylib and returns a referenece to it.
Definition: Core.h:1799
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:524
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization pseudo-symbol, if any.
Definition: Core.h:560
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
Definition: Core.h:546
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
Definition: Core.h:673
virtual StringRef getName() const =0
Return the name of this materialization unit.
SymbolFlagsMap SymbolFlags
Definition: Core.h:729
virtual void materialize(std::unique_ptr< MaterializationResponsibility > R)=0
Implementations of this method should materialize all symbols in the materialzation unit,...
const SymbolStringPtr & getInitializerSymbol() const
Returns the initialization symbol for this MaterializationUnit (if any).
Definition: Core.h:706
An ObjectLayer implementation built on JITLink.
ObjectLinkingLayer & addPlugin(std::unique_ptr< Plugin > P)
Add a pass-config modifier.
void emit(std::unique_ptr< MaterializationResponsibility > R, std::unique_ptr< MemoryBuffer > O) override
Emit an object file.
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:1841
API to remove / transfer ownership of JIT resources.
Definition: Core.h:53
JITDylib & getJITDylib() const
Return the JITDylib targeted by this tracker.
Definition: Core.h:68
static Expected< std::unique_ptr< StaticLibraryDefinitionGenerator > > Load(ObjectLayer &L, const char *FileName, GetObjectFileInterface GetObjFileInterface=GetObjectFileInterface())
Try to create a StaticLibraryDefinitionGenerator from the given path.
A set of symbols to look up, each associated with a SymbolLookupFlags value.
Definition: Core.h:180
SymbolLookupSet & add(SymbolStringPtr Name, SymbolLookupFlags Flags=SymbolLookupFlags::RequiredSymbol)
Add an element to the set.
Definition: Core.h:241
Pointer to a pooled string representing a symbol name.
SPS tag type for expecteds, which are either a T or a string representing an error.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Key
PAL metadata keys.
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:163
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:159
std::unique_ptr< ReExportsMaterializationUnit > symbolAliases(SymbolAliasMap Aliases)
Create a ReExportsMaterializationUnit with the given aliases.
Definition: Core.h:817
std::unique_ptr< AbsoluteSymbolsMaterializationUnit > absoluteSymbols(SymbolMap Symbols)
Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
Definition: Core.h:771
StringRef ELFEHFrameSectionName
std::vector< ELFNixJITDylibDeinitializers > ELFNixJITDylibDeinitializerSequence
static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, ArrayRef< std::pair< const char *, const char * > > AL)
StringRef ELFThreadDataSectionName
RegisterDependenciesFunction NoDependenciesToRegister
This can be used as the value for a RegisterDependenciesFunction if there are no dependants to regist...
Definition: Core.cpp:35
@ Ready
Emitted to memory, but waiting on transitive dependencies.
std::vector< ELFNixJITDylibInitializers > ELFNixJITDylibInitializerSequence
bool isELFInitializerSection(StringRef SecName)
value_type byte_swap(value_type value, endianness endian)
Definition: Endian.h:49
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:511
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
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:1946
Definition: BitVector.h:858
StringMap< SectionList > InitSections