1 //===------ ELFNixPlatform.cpp - Utilities for executing MachO in Orc -----===//
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
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"
23 #define DEBUG_TYPE "orc"
26 using namespace llvm::orc
;
27 using namespace llvm::orc::shared
;
31 class DSOHandleMaterializationUnit
: public MaterializationUnit
{
33 DSOHandleMaterializationUnit(ELFNixPlatform
&ENP
,
34 const SymbolStringPtr
&DSOHandleSymbol
)
35 : MaterializationUnit(
36 createDSOHandleSectionInterface(ENP
, DSOHandleSymbol
)),
39 StringRef
getName() const override
{ return "DSOHandleMU"; }
41 void materialize(std::unique_ptr
<MaterializationResponsibility
> R
) override
{
43 support::endianness Endianness
;
44 jitlink::Edge::Kind EdgeKind
;
45 const auto &TT
= ENP
.getExecutionSession().getTargetTriple();
47 switch (TT
.getArch()) {
50 Endianness
= support::endianness::little
;
51 EdgeKind
= jitlink::x86_64::Pointer64
;
55 Endianness
= support::endianness::little
;
56 EdgeKind
= jitlink::aarch64::Pointer64
;
60 Endianness
= support::endianness::big
;
61 EdgeKind
= jitlink::ppc64::Pointer64
;
65 Endianness
= support::endianness::little
;
66 EdgeKind
= jitlink::ppc64::Pointer64
;
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(),
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
{}
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
),
101 ArrayRef
<char> getDSOHandleContent(size_t PointerSize
) {
102 static const char Content
[8] = {0};
103 assert(PointerSize
<= sizeof Content
);
104 return {Content
, PointerSize
};
110 } // end anonymous namespace
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
));
155 return std::move(Err
);
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
) {
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();
190 return Error::success();
192 RegisteredInitSymbols
[&JD
].add(InitSym
,
193 SymbolLookupFlags::WeaklyReferencedSymbol
);
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());
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()) {
251 case Triple::aarch64
:
252 // FIXME: jitlink for ppc64 hasn't been well tested, leave it unsupported
254 case Triple::ppc64le
:
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
)) {
280 RegisteredInitSymbols
[&PlatformJD
].add(
281 DSOHandleSymbol
, SymbolLookupFlags::WeaklyReferencedSymbol
);
283 // Associate wrapper function tags with JIT-side function implementations.
284 if (auto E2
= associateRuntimeSupportFunctions(PlatformJD
)) {
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
)) {
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
)) {
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();
349 SendResult(DFSLinkOrder
.takeError());
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
366 if (NewInitSymbols
.empty()) {
367 getInitializersBuildSequencePhase(std::move(SendResult
), JD
,
368 std::move(*DFSLinkOrder
));
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 {
376 SendResult(std::move(Err
));
378 getInitializersLookupPhase(std::move(SendResult
), JD
);
380 ES
, std::move(NewInitSymbols
));
383 void ELFNixPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult
,
386 dbgs() << "ELFNixPlatform::rt_getInitializers(\"" << JDName
<< "\")\n";
389 JITDylib
*JD
= ES
.getJITDylibByName(JDName
);
392 dbgs() << " No such JITDylib \"" << JDName
<< "\". Sending error.\n";
394 SendResult(make_error
<StringError
>("No JITDylib named " + JDName
,
395 inconvertibleErrorCode()));
399 getInitializersLookupPhase(std::move(SendResult
), *JD
);
402 void ELFNixPlatform::rt_getDeinitializers(
403 SendDeinitializerSequenceFn SendResult
, ExecutorAddr Handle
) {
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())
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()));
425 SendResult(ELFNixJITDylibDeinitializerSequence());
428 void ELFNixPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult
,
430 StringRef SymbolName
) {
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())
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()));
452 // Use functor class to work around XL build compiler issue on AIX.
453 class RtLookupNotifyComplete
{
455 RtLookupNotifyComplete(SendSymbolAddressFn
&&SendResult
)
456 : SendResult(std::move(SendResult
)) {}
457 void operator()(Expected
<SymbolMap
> Result
) {
459 assert(Result
->size() == 1 && "Unexpected result map count");
460 SendResult(Result
->begin()->second
.getAddress());
462 SendResult(Result
.takeError());
467 SendSymbolAddressFn SendResult
;
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
);
508 return PJDDSOHandle
.takeError();
510 if (auto Err
= ES
.callSPSWrapper
<void(uint64_t)>(
511 orc_rt_elfnix_platform_bootstrap
,
512 PJDDSOHandle
->getAddress().getValue()))
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
))
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.
546 JD
.withLinkOrderDo([](const JITDylibSearchOrder
&SO
) { return SO
; });
547 if (auto Err
= ES
.lookup(SearchOrder
, DSOHandleSymbol
).takeError())
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 "
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
))
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
);
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.
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
);
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
))
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
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
);
691 POSR
.EHFrameSection
= R
.getRange();
694 // Get a pointer to the thread data section if there is one. It will be used
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
);
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
);
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
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
))
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()))
746 // Make a pass over live symbols in the section: those blocks are already
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.
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())
820 if (auto KeyOrErr
= MP
.createPThreadKey())
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
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.