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