1 //===------ MachOPlatform.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/MachOPlatform.h"
11 #include "llvm/BinaryFormat/MachO.h"
12 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
13 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
14 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
15 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
16 #include "llvm/Support/BinaryByteStream.h"
17 #include "llvm/Support/Debug.h"
19 #define DEBUG_TYPE "orc"
22 using namespace llvm::orc
;
23 using namespace llvm::orc::shared
;
27 class MachOHeaderMaterializationUnit
: public MaterializationUnit
{
29 MachOHeaderMaterializationUnit(MachOPlatform
&MOP
,
30 const SymbolStringPtr
&HeaderStartSymbol
)
31 : MaterializationUnit(createHeaderSymbols(MOP
, HeaderStartSymbol
),
35 StringRef
getName() const override
{ return "MachOHeaderMU"; }
37 void materialize(std::unique_ptr
<MaterializationResponsibility
> R
) override
{
39 support::endianness Endianness
;
41 MOP
.getExecutionSession().getExecutorProcessControl().getTargetTriple();
43 switch (TT
.getArch()) {
47 Endianness
= support::endianness::little
;
50 llvm_unreachable("Unrecognized architecture");
53 auto G
= std::make_unique
<jitlink::LinkGraph
>(
54 "<MachOHeaderMU>", TT
, PointerSize
, Endianness
,
55 jitlink::getGenericEdgeKindName
);
56 auto &HeaderSection
= G
->createSection("__header", sys::Memory::MF_READ
);
57 auto &HeaderBlock
= createHeaderBlock(*G
, HeaderSection
);
59 // Init symbol is header-start symbol.
60 G
->addDefinedSymbol(HeaderBlock
, 0, *R
->getInitializerSymbol(),
61 HeaderBlock
.getSize(), jitlink::Linkage::Strong
,
62 jitlink::Scope::Default
, false, true);
63 for (auto &HS
: AdditionalHeaderSymbols
)
64 G
->addDefinedSymbol(HeaderBlock
, HS
.Offset
, HS
.Name
,
65 HeaderBlock
.getSize(), jitlink::Linkage::Strong
,
66 jitlink::Scope::Default
, false, true);
68 MOP
.getObjectLinkingLayer().emit(std::move(R
), std::move(G
));
71 void discard(const JITDylib
&JD
, const SymbolStringPtr
&Sym
) override
{}
79 static constexpr HeaderSymbol AdditionalHeaderSymbols
[] = {
80 {"___mh_executable_header", 0}};
82 static jitlink::Block
&createHeaderBlock(jitlink::LinkGraph
&G
,
83 jitlink::Section
&HeaderSection
) {
84 MachO::mach_header_64 Hdr
;
85 Hdr
.magic
= MachO::MH_MAGIC_64
;
86 switch (G
.getTargetTriple().getArch()) {
88 Hdr
.cputype
= MachO::CPU_TYPE_ARM64
;
89 Hdr
.cpusubtype
= MachO::CPU_SUBTYPE_ARM64_ALL
;
92 Hdr
.cputype
= MachO::CPU_TYPE_X86_64
;
93 Hdr
.cpusubtype
= MachO::CPU_SUBTYPE_X86_64_ALL
;
96 llvm_unreachable("Unrecognized architecture");
98 Hdr
.filetype
= MachO::MH_DYLIB
; // Custom file type?
104 if (G
.getEndianness() != support::endian::system_endianness())
105 MachO::swapStruct(Hdr
);
107 auto HeaderContent
= G
.allocateString(
108 StringRef(reinterpret_cast<const char *>(&Hdr
), sizeof(Hdr
)));
110 return G
.createContentBlock(HeaderSection
, HeaderContent
, 0, 8, 0);
113 static SymbolFlagsMap
114 createHeaderSymbols(MachOPlatform
&MOP
,
115 const SymbolStringPtr
&HeaderStartSymbol
) {
116 SymbolFlagsMap HeaderSymbolFlags
;
118 HeaderSymbolFlags
[HeaderStartSymbol
] = JITSymbolFlags::Exported
;
119 for (auto &HS
: AdditionalHeaderSymbols
)
120 HeaderSymbolFlags
[MOP
.getExecutionSession().intern(HS
.Name
)] =
121 JITSymbolFlags::Exported
;
123 return HeaderSymbolFlags
;
129 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
130 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols
[];
132 StringRef EHFrameSectionName
= "__TEXT,__eh_frame";
133 StringRef ModInitFuncSectionName
= "__DATA,__mod_init_func";
134 StringRef ObjCClassListSectionName
= "__DATA,__objc_classlist";
135 StringRef ObjCImageInfoSectionName
= "__DATA,__objc_image_info";
136 StringRef ObjCSelRefsSectionName
= "__DATA,__objc_selrefs";
137 StringRef Swift5ProtoSectionName
= "__TEXT,__swift5_proto";
138 StringRef Swift5ProtosSectionName
= "__TEXT,__swift5_protos";
139 StringRef ThreadBSSSectionName
= "__DATA,__thread_bss";
140 StringRef ThreadDataSectionName
= "__DATA,__thread_data";
141 StringRef ThreadVarsSectionName
= "__DATA,__thread_vars";
143 StringRef InitSectionNames
[] = {
144 ModInitFuncSectionName
, ObjCSelRefsSectionName
, ObjCClassListSectionName
,
145 Swift5ProtosSectionName
, Swift5ProtoSectionName
};
147 } // end anonymous namespace
152 Expected
<std::unique_ptr
<MachOPlatform
>>
153 MachOPlatform::Create(ExecutionSession
&ES
, ObjectLinkingLayer
&ObjLinkingLayer
,
154 JITDylib
&PlatformJD
, const char *OrcRuntimePath
,
155 Optional
<SymbolAliasMap
> RuntimeAliases
) {
157 auto &EPC
= ES
.getExecutorProcessControl();
159 // If the target is not supported then bail out immediately.
160 if (!supportedTarget(EPC
.getTargetTriple()))
161 return make_error
<StringError
>("Unsupported MachOPlatform triple: " +
162 EPC
.getTargetTriple().str(),
163 inconvertibleErrorCode());
165 // Create default aliases if the caller didn't supply any.
167 RuntimeAliases
= standardPlatformAliases(ES
);
169 // Define the aliases.
170 if (auto Err
= PlatformJD
.define(symbolAliases(std::move(*RuntimeAliases
))))
171 return std::move(Err
);
173 // Add JIT-dispatch function support symbols.
174 if (auto Err
= PlatformJD
.define(absoluteSymbols(
175 {{ES
.intern("___orc_rt_jit_dispatch"),
176 {EPC
.getJITDispatchInfo().JITDispatchFunctionAddress
.getValue(),
177 JITSymbolFlags::Exported
}},
178 {ES
.intern("___orc_rt_jit_dispatch_ctx"),
179 {EPC
.getJITDispatchInfo().JITDispatchContextAddress
.getValue(),
180 JITSymbolFlags::Exported
}}})))
181 return std::move(Err
);
183 // Create a generator for the ORC runtime archive.
184 auto OrcRuntimeArchiveGenerator
= StaticLibraryDefinitionGenerator::Load(
185 ObjLinkingLayer
, OrcRuntimePath
, EPC
.getTargetTriple());
186 if (!OrcRuntimeArchiveGenerator
)
187 return OrcRuntimeArchiveGenerator
.takeError();
189 // Create the instance.
190 Error Err
= Error::success();
191 auto P
= std::unique_ptr
<MachOPlatform
>(
192 new MachOPlatform(ES
, ObjLinkingLayer
, PlatformJD
,
193 std::move(*OrcRuntimeArchiveGenerator
), Err
));
195 return std::move(Err
);
199 Error
MachOPlatform::setupJITDylib(JITDylib
&JD
) {
200 return JD
.define(std::make_unique
<MachOHeaderMaterializationUnit
>(
201 *this, MachOHeaderStartSymbol
));
204 Error
MachOPlatform::notifyAdding(ResourceTracker
&RT
,
205 const MaterializationUnit
&MU
) {
206 auto &JD
= RT
.getJITDylib();
207 const auto &InitSym
= MU
.getInitializerSymbol();
209 return Error::success();
211 RegisteredInitSymbols
[&JD
].add(InitSym
,
212 SymbolLookupFlags::WeaklyReferencedSymbol
);
214 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym
<< " for MU "
215 << MU
.getName() << "\n";
217 return Error::success();
220 Error
MachOPlatform::notifyRemoving(ResourceTracker
&RT
) {
221 llvm_unreachable("Not supported yet");
224 static void addAliases(ExecutionSession
&ES
, SymbolAliasMap
&Aliases
,
225 ArrayRef
<std::pair
<const char *, const char *>> AL
) {
226 for (auto &KV
: AL
) {
227 auto AliasName
= ES
.intern(KV
.first
);
228 assert(!Aliases
.count(AliasName
) && "Duplicate symbol name in alias map");
229 Aliases
[std::move(AliasName
)] = {ES
.intern(KV
.second
),
230 JITSymbolFlags::Exported
};
234 SymbolAliasMap
MachOPlatform::standardPlatformAliases(ExecutionSession
&ES
) {
235 SymbolAliasMap Aliases
;
236 addAliases(ES
, Aliases
, requiredCXXAliases());
237 addAliases(ES
, Aliases
, standardRuntimeUtilityAliases());
241 ArrayRef
<std::pair
<const char *, const char *>>
242 MachOPlatform::requiredCXXAliases() {
243 static const std::pair
<const char *, const char *> RequiredCXXAliases
[] = {
244 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
246 return ArrayRef
<std::pair
<const char *, const char *>>(RequiredCXXAliases
);
249 ArrayRef
<std::pair
<const char *, const char *>>
250 MachOPlatform::standardRuntimeUtilityAliases() {
251 static const std::pair
<const char *, const char *>
252 StandardRuntimeUtilityAliases
[] = {
253 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
254 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
256 return ArrayRef
<std::pair
<const char *, const char *>>(
257 StandardRuntimeUtilityAliases
);
260 bool MachOPlatform::isInitializerSection(StringRef SegName
,
261 StringRef SectName
) {
262 for (auto &Name
: InitSectionNames
) {
263 if (Name
.startswith(SegName
) && Name
.substr(7) == SectName
)
269 bool MachOPlatform::supportedTarget(const Triple
&TT
) {
270 switch (TT
.getArch()) {
278 MachOPlatform::MachOPlatform(
279 ExecutionSession
&ES
, ObjectLinkingLayer
&ObjLinkingLayer
,
280 JITDylib
&PlatformJD
,
281 std::unique_ptr
<DefinitionGenerator
> OrcRuntimeGenerator
, Error
&Err
)
282 : ES(ES
), ObjLinkingLayer(ObjLinkingLayer
),
283 MachOHeaderStartSymbol(ES
.intern("___dso_handle")) {
284 ErrorAsOutParameter
_(&Err
);
286 ObjLinkingLayer
.addPlugin(std::make_unique
<MachOPlatformPlugin
>(*this));
288 PlatformJD
.addGenerator(std::move(OrcRuntimeGenerator
));
290 // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
291 // the platform now), so set it up.
292 if (auto E2
= setupJITDylib(PlatformJD
)) {
297 RegisteredInitSymbols
[&PlatformJD
].add(
298 MachOHeaderStartSymbol
, SymbolLookupFlags::WeaklyReferencedSymbol
);
300 // Associate wrapper function tags with JIT-side function implementations.
301 if (auto E2
= associateRuntimeSupportFunctions(PlatformJD
)) {
306 // Lookup addresses of runtime functions callable by the platform,
307 // call the platform bootstrap function to initialize the platform-state
308 // object in the executor.
309 if (auto E2
= bootstrapMachORuntime(PlatformJD
)) {
315 Error
MachOPlatform::associateRuntimeSupportFunctions(JITDylib
&PlatformJD
) {
316 ExecutionSession::JITDispatchHandlerAssociationMap WFs
;
318 using GetInitializersSPSSig
=
319 SPSExpected
<SPSMachOJITDylibInitializerSequence
>(SPSString
);
320 WFs
[ES
.intern("___orc_rt_macho_get_initializers_tag")] =
321 ES
.wrapAsyncWithSPS
<GetInitializersSPSSig
>(
322 this, &MachOPlatform::rt_getInitializers
);
324 using GetDeinitializersSPSSig
=
325 SPSExpected
<SPSMachOJITDylibDeinitializerSequence
>(SPSExecutorAddress
);
326 WFs
[ES
.intern("___orc_rt_macho_get_deinitializers_tag")] =
327 ES
.wrapAsyncWithSPS
<GetDeinitializersSPSSig
>(
328 this, &MachOPlatform::rt_getDeinitializers
);
330 using LookupSymbolSPSSig
=
331 SPSExpected
<SPSExecutorAddress
>(SPSExecutorAddress
, SPSString
);
332 WFs
[ES
.intern("___orc_rt_macho_symbol_lookup_tag")] =
333 ES
.wrapAsyncWithSPS
<LookupSymbolSPSSig
>(this,
334 &MachOPlatform::rt_lookupSymbol
);
336 return ES
.registerJITDispatchHandlers(PlatformJD
, std::move(WFs
));
339 void MachOPlatform::getInitializersBuildSequencePhase(
340 SendInitializerSequenceFn SendResult
, JITDylib
&JD
,
341 std::vector
<JITDylibSP
> DFSLinkOrder
) {
342 MachOJITDylibInitializerSequence FullInitSeq
;
344 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
345 for (auto &InitJD
: reverse(DFSLinkOrder
)) {
347 dbgs() << "MachOPlatform: Appending inits for \"" << InitJD
->getName()
348 << "\" to sequence\n";
350 auto ISItr
= InitSeqs
.find(InitJD
.get());
351 if (ISItr
!= InitSeqs
.end()) {
352 FullInitSeq
.emplace_back(std::move(ISItr
->second
));
353 InitSeqs
.erase(ISItr
);
358 SendResult(std::move(FullInitSeq
));
361 void MachOPlatform::getInitializersLookupPhase(
362 SendInitializerSequenceFn SendResult
, JITDylib
&JD
) {
364 auto DFSLinkOrder
= JD
.getDFSLinkOrder();
365 DenseMap
<JITDylib
*, SymbolLookupSet
> NewInitSymbols
;
366 ES
.runSessionLocked([&]() {
367 for (auto &InitJD
: DFSLinkOrder
) {
368 auto RISItr
= RegisteredInitSymbols
.find(InitJD
.get());
369 if (RISItr
!= RegisteredInitSymbols
.end()) {
370 NewInitSymbols
[InitJD
.get()] = std::move(RISItr
->second
);
371 RegisteredInitSymbols
.erase(RISItr
);
376 // If there are no further init symbols to look up then move on to the next
378 if (NewInitSymbols
.empty()) {
379 getInitializersBuildSequencePhase(std::move(SendResult
), JD
,
380 std::move(DFSLinkOrder
));
384 // Otherwise issue a lookup and re-run this phase when it completes.
385 lookupInitSymbolsAsync(
386 [this, SendResult
= std::move(SendResult
), &JD
](Error Err
) mutable {
388 SendResult(std::move(Err
));
390 getInitializersLookupPhase(std::move(SendResult
), JD
);
392 ES
, std::move(NewInitSymbols
));
395 void MachOPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult
,
398 dbgs() << "MachOPlatform::rt_getInitializers(\"" << JDName
<< "\")\n";
401 JITDylib
*JD
= ES
.getJITDylibByName(JDName
);
404 dbgs() << " No such JITDylib \"" << JDName
<< "\". Sending error.\n";
406 SendResult(make_error
<StringError
>("No JITDylib named " + JDName
,
407 inconvertibleErrorCode()));
411 getInitializersLookupPhase(std::move(SendResult
), *JD
);
414 void MachOPlatform::rt_getDeinitializers(SendDeinitializerSequenceFn SendResult
,
415 ExecutorAddress Handle
) {
417 dbgs() << "MachOPlatform::rt_getDeinitializers(\""
418 << formatv("{0:x}", Handle
.getValue()) << "\")\n";
421 JITDylib
*JD
= nullptr;
424 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
425 auto I
= HeaderAddrToJITDylib
.find(Handle
.getValue());
426 if (I
!= HeaderAddrToJITDylib
.end())
432 dbgs() << " No JITDylib for handle "
433 << formatv("{0:x}", Handle
.getValue()) << "\n";
435 SendResult(make_error
<StringError
>("No JITDylib associated with handle " +
436 formatv("{0:x}", Handle
.getValue()),
437 inconvertibleErrorCode()));
441 SendResult(MachOJITDylibDeinitializerSequence());
444 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult
,
445 ExecutorAddress Handle
,
446 StringRef SymbolName
) {
448 dbgs() << "MachOPlatform::rt_lookupSymbol(\""
449 << formatv("{0:x}", Handle
.getValue()) << "\")\n";
452 JITDylib
*JD
= nullptr;
455 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
456 auto I
= HeaderAddrToJITDylib
.find(Handle
.getValue());
457 if (I
!= HeaderAddrToJITDylib
.end())
463 dbgs() << " No JITDylib for handle "
464 << formatv("{0:x}", Handle
.getValue()) << "\n";
466 SendResult(make_error
<StringError
>("No JITDylib associated with handle " +
467 formatv("{0:x}", Handle
.getValue()),
468 inconvertibleErrorCode()));
472 // Use functor class to work around XL build compiler issue on AIX.
473 class RtLookupNotifyComplete
{
475 RtLookupNotifyComplete(SendSymbolAddressFn
&&SendResult
)
476 : SendResult(std::move(SendResult
)) {}
477 void operator()(Expected
<SymbolMap
> Result
) {
479 assert(Result
->size() == 1 && "Unexpected result map count");
480 SendResult(ExecutorAddress(Result
->begin()->second
.getAddress()));
482 SendResult(Result
.takeError());
487 SendSymbolAddressFn SendResult
;
490 // FIXME: Proper mangling.
491 auto MangledName
= ("_" + SymbolName
).str();
493 LookupKind::DLSym
, {{JD
, JITDylibLookupFlags::MatchExportedSymbolsOnly
}},
494 SymbolLookupSet(ES
.intern(MangledName
)), SymbolState::Ready
,
495 RtLookupNotifyComplete(std::move(SendResult
)), NoDependenciesToRegister
);
498 Error
MachOPlatform::bootstrapMachORuntime(JITDylib
&PlatformJD
) {
500 if (auto Err
= lookupAndRecordAddrs(
501 ES
, LookupKind::Static
, makeJITDylibSearchOrder(&PlatformJD
),
502 {{ES
.intern("___orc_rt_macho_platform_bootstrap"),
503 &orc_rt_macho_platform_bootstrap
},
504 {ES
.intern("___orc_rt_macho_platform_shutdown"),
505 &orc_rt_macho_platform_shutdown
},
506 {ES
.intern("___orc_rt_macho_register_object_sections"),
507 &orc_rt_macho_register_object_sections
},
508 {ES
.intern("___orc_rt_macho_create_pthread_key"),
509 &orc_rt_macho_create_pthread_key
}}))
513 ES
.callSPSWrapper
<void()>(orc_rt_macho_platform_bootstrap
.getValue()))
516 // FIXME: Ordering is fuzzy here. We're probably best off saying
517 // "behavior is undefined if code that uses the runtime is added before
518 // the platform constructor returns", then move all this to the constructor.
519 RuntimeBootstrapped
= true;
520 std::vector
<MachOPerObjectSectionsToRegister
> DeferredPOSRs
;
522 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
523 DeferredPOSRs
= std::move(BootstrapPOSRs
);
526 for (auto &D
: DeferredPOSRs
)
527 if (auto Err
= registerPerObjectSections(D
))
530 return Error::success();
533 Error
MachOPlatform::registerInitInfo(
534 JITDylib
&JD
, ExecutorAddress ObjCImageInfoAddr
,
535 ArrayRef
<jitlink::Section
*> InitSections
) {
537 std::unique_lock
<std::mutex
> Lock(PlatformMutex
);
539 MachOJITDylibInitializers
*InitSeq
= nullptr;
541 auto I
= InitSeqs
.find(&JD
);
542 if (I
== InitSeqs
.end()) {
543 // If there's no init sequence entry yet then we need to look up the
544 // header symbol to force creation of one.
548 JD
.withLinkOrderDo([](const JITDylibSearchOrder
&SO
) { return SO
; });
549 if (auto Err
= ES
.lookup(SearchOrder
, MachOHeaderStartSymbol
).takeError())
553 I
= InitSeqs
.find(&JD
);
554 assert(I
!= InitSeqs
.end() &&
555 "Entry missing after header symbol lookup?");
557 InitSeq
= &I
->second
;
560 InitSeq
->ObjCImageInfoAddress
= ObjCImageInfoAddr
;
562 for (auto *Sec
: InitSections
) {
563 // FIXME: Avoid copy here.
564 jitlink::SectionRange
R(*Sec
);
565 InitSeq
->InitSections
[Sec
->getName()].push_back(
566 {ExecutorAddress(R
.getStart()), ExecutorAddress(R
.getEnd())});
569 return Error::success();
572 Error
MachOPlatform::registerPerObjectSections(
573 const MachOPerObjectSectionsToRegister
&POSR
) {
575 if (!orc_rt_macho_register_object_sections
)
576 return make_error
<StringError
>("Attempting to register per-object "
577 "sections, but runtime support has not "
579 inconvertibleErrorCode());
581 Error ErrResult
= Error::success();
582 if (auto Err
= ES
.callSPSWrapper
<shared::SPSError(
583 SPSMachOPerObjectSectionsToRegister
)>(
584 orc_rt_macho_register_object_sections
.getValue(), ErrResult
, POSR
))
589 Expected
<uint64_t> MachOPlatform::createPThreadKey() {
590 if (!orc_rt_macho_create_pthread_key
)
591 return make_error
<StringError
>(
592 "Attempting to create pthread key in target, but runtime support has "
593 "not been loaded yet",
594 inconvertibleErrorCode());
596 Expected
<uint64_t> Result(0);
597 if (auto Err
= ES
.callSPSWrapper
<SPSExpected
<uint64_t>(void)>(
598 orc_rt_macho_create_pthread_key
.getValue(), Result
))
599 return std::move(Err
);
603 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
604 MaterializationResponsibility
&MR
, jitlink::LinkGraph
&LG
,
605 jitlink::PassConfiguration
&Config
) {
607 // If the initializer symbol is the MachOHeader start symbol then just add
608 // the macho header support passes.
609 if (MR
.getInitializerSymbol() == MP
.MachOHeaderStartSymbol
) {
610 addMachOHeaderSupportPasses(MR
, Config
);
611 // The header materialization unit doesn't require any other support, so we
612 // can bail out early.
616 // If the object contains initializers then add passes to record them.
617 if (MR
.getInitializerSymbol())
618 addInitializerSupportPasses(MR
, Config
);
620 // Add passes for eh-frame and TLV support.
621 addEHAndTLVSupportPasses(MR
, Config
);
624 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
625 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
626 MaterializationResponsibility
&MR
) {
627 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
628 auto I
= InitSymbolDeps
.find(&MR
);
629 if (I
!= InitSymbolDeps
.end()) {
630 SyntheticSymbolDependenciesMap Result
;
631 Result
[MR
.getInitializerSymbol()] = std::move(I
->second
);
632 InitSymbolDeps
.erase(&MR
);
635 return SyntheticSymbolDependenciesMap();
638 void MachOPlatform::MachOPlatformPlugin::addInitializerSupportPasses(
639 MaterializationResponsibility
&MR
, jitlink::PassConfiguration
&Config
) {
641 /// Preserve init sections.
642 Config
.PrePrunePasses
.push_back([this, &MR
](jitlink::LinkGraph
&G
) {
643 if (auto Err
= preserveInitSections(G
, MR
))
645 return processObjCImageInfo(G
, MR
);
648 Config
.PostFixupPasses
.push_back(
649 [this, &JD
= MR
.getTargetJITDylib()](jitlink::LinkGraph
&G
) {
650 return registerInitSections(G
, JD
);
654 void MachOPlatform::MachOPlatformPlugin::addMachOHeaderSupportPasses(
655 MaterializationResponsibility
&MR
, jitlink::PassConfiguration
&Config
) {
657 Config
.PostAllocationPasses
.push_back([this, &JD
= MR
.getTargetJITDylib()](
658 jitlink::LinkGraph
&G
) -> Error
{
659 auto I
= llvm::find_if(G
.defined_symbols(), [this](jitlink::Symbol
*Sym
) {
660 return Sym
->getName() == *MP
.MachOHeaderStartSymbol
;
662 assert(I
!= G
.defined_symbols().end() &&
663 "Missing MachO header start symbol");
665 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
666 JITTargetAddress HeaderAddr
= (*I
)->getAddress();
667 MP
.HeaderAddrToJITDylib
[HeaderAddr
] = &JD
;
668 assert(!MP
.InitSeqs
.count(&JD
) && "InitSeq entry for JD already exists");
670 std::make_pair(&JD
, MachOJITDylibInitializers(
671 JD
.getName(), ExecutorAddress(HeaderAddr
))));
673 return Error::success();
677 void MachOPlatform::MachOPlatformPlugin::addEHAndTLVSupportPasses(
678 MaterializationResponsibility
&MR
, jitlink::PassConfiguration
&Config
) {
680 // Insert TLV lowering at the start of the PostPrunePasses, since we want
681 // it to run before GOT/PLT lowering.
682 Config
.PostPrunePasses
.insert(
683 Config
.PostPrunePasses
.begin(),
684 [this, &JD
= MR
.getTargetJITDylib()](jitlink::LinkGraph
&G
) {
685 return fixTLVSectionsAndEdges(G
, JD
);
688 // Add a pass to register the final addresses of the eh-frame and TLV sections
690 Config
.PostFixupPasses
.push_back([this](jitlink::LinkGraph
&G
) -> Error
{
691 MachOPerObjectSectionsToRegister POSR
;
693 if (auto *EHFrameSection
= G
.findSectionByName(EHFrameSectionName
)) {
694 jitlink::SectionRange
R(*EHFrameSection
);
696 POSR
.EHFrameSection
= {ExecutorAddress(R
.getStart()),
697 ExecutorAddress(R
.getEnd())};
700 // Get a pointer to the thread data section if there is one. It will be used
702 jitlink::Section
*ThreadDataSection
=
703 G
.findSectionByName(ThreadDataSectionName
);
705 // Handle thread BSS section if there is one.
706 if (auto *ThreadBSSSection
= G
.findSectionByName(ThreadBSSSectionName
)) {
707 // If there's already a thread data section in this graph then merge the
708 // thread BSS section content into it, otherwise just treat the thread
709 // BSS section as the thread data section.
710 if (ThreadDataSection
)
711 G
.mergeSections(*ThreadDataSection
, *ThreadBSSSection
);
713 ThreadDataSection
= ThreadBSSSection
;
716 // Having merged thread BSS (if present) and thread data (if present),
717 // record the resulting section range.
718 if (ThreadDataSection
) {
719 jitlink::SectionRange
R(*ThreadDataSection
);
721 POSR
.ThreadDataSection
= {ExecutorAddress(R
.getStart()),
722 ExecutorAddress(R
.getEnd())};
725 if (POSR
.EHFrameSection
.StartAddress
||
726 POSR
.ThreadDataSection
.StartAddress
) {
728 // If we're still bootstrapping the runtime then just record this
730 if (!MP
.RuntimeBootstrapped
) {
731 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
732 MP
.BootstrapPOSRs
.push_back(POSR
);
733 return Error::success();
736 // Otherwise register it immediately.
737 if (auto Err
= MP
.registerPerObjectSections(POSR
))
741 return Error::success();
745 Error
MachOPlatform::MachOPlatformPlugin::preserveInitSections(
746 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
748 JITLinkSymbolSet InitSectionSymbols
;
749 for (auto &InitSectionName
: InitSectionNames
) {
750 // Skip non-init sections.
751 auto *InitSection
= G
.findSectionByName(InitSectionName
);
755 // Make a pass over live symbols in the section: those blocks are already
757 DenseSet
<jitlink::Block
*> AlreadyLiveBlocks
;
758 for (auto &Sym
: InitSection
->symbols()) {
759 auto &B
= Sym
->getBlock();
760 if (Sym
->isLive() && Sym
->getOffset() == 0 &&
761 Sym
->getSize() == B
.getSize() && !AlreadyLiveBlocks
.count(&B
)) {
762 InitSectionSymbols
.insert(Sym
);
763 AlreadyLiveBlocks
.insert(&B
);
767 // Add anonymous symbols to preserve any not-already-preserved blocks.
768 for (auto *B
: InitSection
->blocks())
769 if (!AlreadyLiveBlocks
.count(B
))
770 InitSectionSymbols
.insert(
771 &G
.addAnonymousSymbol(*B
, 0, B
->getSize(), false, true));
774 if (!InitSectionSymbols
.empty()) {
775 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
776 InitSymbolDeps
[&MR
] = std::move(InitSectionSymbols
);
779 return Error::success();
782 Error
MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
783 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
785 // If there's an ObjC imagine info then either
786 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
787 // this case we name and record it.
789 // (2) We already have a recorded __objc_imageinfo for this JITDylib,
790 // in which case we just verify it.
791 auto *ObjCImageInfo
= G
.findSectionByName(ObjCImageInfoSectionName
);
793 return Error::success();
795 auto ObjCImageInfoBlocks
= ObjCImageInfo
->blocks();
797 // Check that the section is not empty if present.
798 if (llvm::empty(ObjCImageInfoBlocks
))
799 return make_error
<StringError
>("Empty " + ObjCImageInfoSectionName
+
800 " section in " + G
.getName(),
801 inconvertibleErrorCode());
803 // Check that there's only one block in the section.
804 if (std::next(ObjCImageInfoBlocks
.begin()) != ObjCImageInfoBlocks
.end())
805 return make_error
<StringError
>("Multiple blocks in " +
806 ObjCImageInfoSectionName
+
807 " section in " + G
.getName(),
808 inconvertibleErrorCode());
810 // Check that the __objc_imageinfo section is unreferenced.
811 // FIXME: We could optimize this check if Symbols had a ref-count.
812 for (auto &Sec
: G
.sections()) {
813 if (&Sec
!= ObjCImageInfo
)
814 for (auto *B
: Sec
.blocks())
815 for (auto &E
: B
->edges())
816 if (E
.getTarget().isDefined() &&
817 &E
.getTarget().getBlock().getSection() == ObjCImageInfo
)
818 return make_error
<StringError
>(ObjCImageInfoSectionName
+
819 " is referenced within file " +
821 inconvertibleErrorCode());
824 auto &ObjCImageInfoBlock
= **ObjCImageInfoBlocks
.begin();
825 auto *ObjCImageInfoData
= ObjCImageInfoBlock
.getContent().data();
826 auto Version
= support::endian::read32(ObjCImageInfoData
, G
.getEndianness());
828 support::endian::read32(ObjCImageInfoData
+ 4, G
.getEndianness());
830 // Lock the mutex while we verify / update the ObjCImageInfos map.
831 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
833 auto ObjCImageInfoItr
= ObjCImageInfos
.find(&MR
.getTargetJITDylib());
834 if (ObjCImageInfoItr
!= ObjCImageInfos
.end()) {
835 // We've already registered an __objc_imageinfo section. Verify the
836 // content of this new section matches, then delete it.
837 if (ObjCImageInfoItr
->second
.first
!= Version
)
838 return make_error
<StringError
>(
839 "ObjC version in " + G
.getName() +
840 " does not match first registered version",
841 inconvertibleErrorCode());
842 if (ObjCImageInfoItr
->second
.second
!= Flags
)
843 return make_error
<StringError
>("ObjC flags in " + G
.getName() +
844 " do not match first registered flags",
845 inconvertibleErrorCode());
847 // __objc_imageinfo is valid. Delete the block.
848 for (auto *S
: ObjCImageInfo
->symbols())
849 G
.removeDefinedSymbol(*S
);
850 G
.removeBlock(ObjCImageInfoBlock
);
852 // We haven't registered an __objc_imageinfo section yet. Register and
853 // move on. The section should already be marked no-dead-strip.
854 ObjCImageInfos
[&MR
.getTargetJITDylib()] = std::make_pair(Version
, Flags
);
857 return Error::success();
860 Error
MachOPlatform::MachOPlatformPlugin::registerInitSections(
861 jitlink::LinkGraph
&G
, JITDylib
&JD
) {
863 ExecutorAddress ObjCImageInfoAddr
;
864 SmallVector
<jitlink::Section
*> InitSections
;
866 if (auto *ObjCImageInfoSec
= G
.findSectionByName(ObjCImageInfoSectionName
)) {
867 if (auto Addr
= jitlink::SectionRange(*ObjCImageInfoSec
).getStart())
868 ObjCImageInfoAddr
.setValue(Addr
);
871 for (auto InitSectionName
: InitSectionNames
)
872 if (auto *Sec
= G
.findSectionByName(InitSectionName
))
873 InitSections
.push_back(Sec
);
875 // Dump the scraped inits.
877 dbgs() << "MachOPlatform: Scraped " << G
.getName() << " init sections:\n";
878 if (ObjCImageInfoAddr
)
879 dbgs() << " " << ObjCImageInfoSectionName
<< ": "
880 << formatv("{0:x}", ObjCImageInfoAddr
.getValue()) << "\n";
881 for (auto *Sec
: InitSections
) {
882 jitlink::SectionRange
R(*Sec
);
883 dbgs() << " " << Sec
->getName() << ": "
884 << formatv("[ {0:x} -- {1:x} ]", R
.getStart(), R
.getEnd()) << "\n";
888 return MP
.registerInitInfo(JD
, ObjCImageInfoAddr
, InitSections
);
891 Error
MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
892 jitlink::LinkGraph
&G
, JITDylib
&JD
) {
894 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
895 for (auto *Sym
: G
.external_symbols())
896 if (Sym
->getName() == "__tlv_bootstrap") {
897 Sym
->setName("___orc_rt_macho_tlv_get_addr");
901 // Store key in __thread_vars struct fields.
902 if (auto *ThreadDataSec
= G
.findSectionByName(ThreadVarsSectionName
)) {
903 Optional
<uint64_t> Key
;
905 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
906 auto I
= MP
.JITDylibToPThreadKey
.find(&JD
);
907 if (I
!= MP
.JITDylibToPThreadKey
.end())
912 if (auto KeyOrErr
= MP
.createPThreadKey())
915 return KeyOrErr
.takeError();
918 uint64_t PlatformKeyBits
=
919 support::endian::byte_swap(*Key
, G
.getEndianness());
921 for (auto *B
: ThreadDataSec
->blocks()) {
922 if (B
->getSize() != 3 * G
.getPointerSize())
923 return make_error
<StringError
>("__thread_vars block at " +
924 formatv("{0:x}", B
->getAddress()) +
925 " has unexpected size",
926 inconvertibleErrorCode());
928 auto NewBlockContent
= G
.allocateBuffer(B
->getSize());
929 llvm::copy(B
->getContent(), NewBlockContent
.data());
930 memcpy(NewBlockContent
.data() + G
.getPointerSize(), &PlatformKeyBits
,
932 B
->setContent(NewBlockContent
);
936 // Transform any TLV edges into GOT edges.
937 for (auto *B
: G
.blocks())
938 for (auto &E
: B
->edges())
940 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
)
941 E
.setKind(jitlink::x86_64::
942 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable
);
944 return Error::success();
947 } // End namespace orc.
948 } // End namespace llvm.