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/MachO.h"
13 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
14 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
15 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
16 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
17 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.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
;
33 using SPSMachOJITDylibDepInfo
= SPSTuple
<bool, SPSSequence
<SPSExecutorAddr
>>;
34 using SPSMachOJITDylibDepInfoMap
=
35 SPSSequence
<SPSTuple
<SPSExecutorAddr
, SPSMachOJITDylibDepInfo
>>;
38 class SPSSerializationTraits
<SPSMachOJITDylibDepInfo
,
39 MachOPlatform::MachOJITDylibDepInfo
> {
41 static size_t size(const MachOPlatform::MachOJITDylibDepInfo
&DDI
) {
42 return SPSMachOJITDylibDepInfo::AsArgList::size(DDI
.Sealed
, DDI
.DepHeaders
);
45 static bool serialize(SPSOutputBuffer
&OB
,
46 const MachOPlatform::MachOJITDylibDepInfo
&DDI
) {
47 return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB
, DDI
.Sealed
,
51 static bool deserialize(SPSInputBuffer
&IB
,
52 MachOPlatform::MachOJITDylibDepInfo
&DDI
) {
53 return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB
, DDI
.Sealed
,
64 std::unique_ptr
<jitlink::LinkGraph
> createPlatformGraph(MachOPlatform
&MOP
,
67 llvm::endianness Endianness
;
68 const auto &TT
= MOP
.getExecutionSession().getTargetTriple();
70 switch (TT
.getArch()) {
74 Endianness
= llvm::endianness::little
;
77 llvm_unreachable("Unrecognized architecture");
80 return std::make_unique
<jitlink::LinkGraph
>(std::move(Name
), TT
, PointerSize
,
82 jitlink::getGenericEdgeKindName
);
85 // Generates a MachO header.
86 class MachOHeaderMaterializationUnit
: public MaterializationUnit
{
88 MachOHeaderMaterializationUnit(MachOPlatform
&MOP
,
89 const SymbolStringPtr
&HeaderStartSymbol
)
90 : MaterializationUnit(createHeaderInterface(MOP
, HeaderStartSymbol
)),
93 StringRef
getName() const override
{ return "MachOHeaderMU"; }
95 void materialize(std::unique_ptr
<MaterializationResponsibility
> R
) override
{
96 auto G
= createPlatformGraph(MOP
, "<MachOHeaderMU>");
97 addMachOHeader(*G
, MOP
, R
->getInitializerSymbol());
98 MOP
.getObjectLinkingLayer().emit(std::move(R
), std::move(G
));
101 void discard(const JITDylib
&JD
, const SymbolStringPtr
&Sym
) override
{}
103 static void addMachOHeader(jitlink::LinkGraph
&G
, MachOPlatform
&MOP
,
104 const SymbolStringPtr
&InitializerSymbol
) {
105 auto &HeaderSection
= G
.createSection("__header", MemProt::Read
);
106 auto &HeaderBlock
= createHeaderBlock(G
, HeaderSection
);
108 // Init symbol is header-start symbol.
109 G
.addDefinedSymbol(HeaderBlock
, 0, *InitializerSymbol
,
110 HeaderBlock
.getSize(), jitlink::Linkage::Strong
,
111 jitlink::Scope::Default
, false, true);
112 for (auto &HS
: AdditionalHeaderSymbols
)
113 G
.addDefinedSymbol(HeaderBlock
, HS
.Offset
, HS
.Name
, HeaderBlock
.getSize(),
114 jitlink::Linkage::Strong
, jitlink::Scope::Default
,
119 struct HeaderSymbol
{
124 static constexpr HeaderSymbol AdditionalHeaderSymbols
[] = {
125 {"___mh_executable_header", 0}};
127 static jitlink::Block
&createHeaderBlock(jitlink::LinkGraph
&G
,
128 jitlink::Section
&HeaderSection
) {
129 MachO::mach_header_64 Hdr
;
130 Hdr
.magic
= MachO::MH_MAGIC_64
;
131 switch (G
.getTargetTriple().getArch()) {
132 case Triple::aarch64
:
133 Hdr
.cputype
= MachO::CPU_TYPE_ARM64
;
134 Hdr
.cpusubtype
= MachO::CPU_SUBTYPE_ARM64_ALL
;
137 Hdr
.cputype
= MachO::CPU_TYPE_X86_64
;
138 Hdr
.cpusubtype
= MachO::CPU_SUBTYPE_X86_64_ALL
;
141 llvm_unreachable("Unrecognized architecture");
143 Hdr
.filetype
= MachO::MH_DYLIB
; // Custom file type?
149 if (G
.getEndianness() != llvm::endianness::native
)
150 MachO::swapStruct(Hdr
);
152 auto HeaderContent
= G
.allocateContent(
153 ArrayRef
<char>(reinterpret_cast<const char *>(&Hdr
), sizeof(Hdr
)));
155 return G
.createContentBlock(HeaderSection
, HeaderContent
, ExecutorAddr(), 8,
159 static MaterializationUnit::Interface
160 createHeaderInterface(MachOPlatform
&MOP
,
161 const SymbolStringPtr
&HeaderStartSymbol
) {
162 SymbolFlagsMap HeaderSymbolFlags
;
164 HeaderSymbolFlags
[HeaderStartSymbol
] = JITSymbolFlags::Exported
;
165 for (auto &HS
: AdditionalHeaderSymbols
)
166 HeaderSymbolFlags
[MOP
.getExecutionSession().intern(HS
.Name
)] =
167 JITSymbolFlags::Exported
;
169 return MaterializationUnit::Interface(std::move(HeaderSymbolFlags
),
176 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
177 MachOHeaderMaterializationUnit::AdditionalHeaderSymbols
[];
179 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
180 class MachOPlatformCompleteBootstrapMaterializationUnit
181 : public MaterializationUnit
{
183 MachOPlatformCompleteBootstrapMaterializationUnit(
184 MachOPlatform
&MOP
, StringRef PlatformJDName
,
185 SymbolStringPtr CompleteBootstrapSymbol
, shared::AllocActions DeferredAAs
,
186 ExecutorAddr PlatformBootstrap
, ExecutorAddr PlatformShutdown
,
187 ExecutorAddr RegisterJITDylib
, ExecutorAddr DeregisterJITDylib
,
188 ExecutorAddr MachOHeaderAddr
)
189 : MaterializationUnit(
190 {{{CompleteBootstrapSymbol
, JITSymbolFlags::None
}}, nullptr}),
191 MOP(MOP
), PlatformJDName(PlatformJDName
),
192 CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol
)),
193 DeferredAAs(std::move(DeferredAAs
)),
194 PlatformBootstrap(PlatformBootstrap
),
195 PlatformShutdown(PlatformShutdown
), RegisterJITDylib(RegisterJITDylib
),
196 DeregisterJITDylib(DeregisterJITDylib
),
197 MachOHeaderAddr(MachOHeaderAddr
) {}
199 StringRef
getName() const override
{
200 return "MachOPlatformCompleteBootstrap";
203 void materialize(std::unique_ptr
<MaterializationResponsibility
> R
) override
{
204 using namespace jitlink
;
205 auto G
= createPlatformGraph(MOP
, "<OrcRTCompleteBootstrap>");
206 auto &PlaceholderSection
=
207 G
->createSection("__orc_rt_cplt_bs", MemProt::Read
);
208 auto &PlaceholderBlock
=
209 G
->createZeroFillBlock(PlaceholderSection
, 1, ExecutorAddr(), 1, 0);
210 G
->addDefinedSymbol(PlaceholderBlock
, 0, *CompleteBootstrapSymbol
, 1,
211 Linkage::Strong
, Scope::Hidden
, false, true);
213 // Reserve space for the stolen actions, plus two extras.
214 G
->allocActions().reserve(DeferredAAs
.size() + 2);
216 // 1. Bootstrap the platform support code.
217 G
->allocActions().push_back(
218 {cantFail(WrapperFunctionCall::Create
<SPSArgList
<>>(PlatformBootstrap
)),
220 WrapperFunctionCall::Create
<SPSArgList
<>>(PlatformShutdown
))});
222 // 2. Register the platform JITDylib.
223 G
->allocActions().push_back(
224 {cantFail(WrapperFunctionCall::Create
<
225 SPSArgList
<SPSString
, SPSExecutorAddr
>>(
226 RegisterJITDylib
, PlatformJDName
, MachOHeaderAddr
)),
227 cantFail(WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddr
>>(
228 DeregisterJITDylib
, MachOHeaderAddr
))});
230 // 3. Add the deferred actions to the graph.
231 std::move(DeferredAAs
.begin(), DeferredAAs
.end(),
232 std::back_inserter(G
->allocActions()));
234 MOP
.getObjectLinkingLayer().emit(std::move(R
), std::move(G
));
237 void discard(const JITDylib
&JD
, const SymbolStringPtr
&Sym
) override
{}
241 StringRef PlatformJDName
;
242 SymbolStringPtr CompleteBootstrapSymbol
;
243 shared::AllocActions DeferredAAs
;
244 ExecutorAddr PlatformBootstrap
;
245 ExecutorAddr PlatformShutdown
;
246 ExecutorAddr RegisterJITDylib
;
247 ExecutorAddr DeregisterJITDylib
;
248 ExecutorAddr MachOHeaderAddr
;
251 static StringRef ObjCRuntimeObjectSectionsData
[] = {
252 MachOObjCCatListSectionName
, MachOObjCClassListSectionName
,
253 MachOObjCClassRefsSectionName
, MachOObjCConstSectionName
,
254 MachOObjCDataSectionName
, MachOObjCSelRefsSectionName
};
256 static StringRef ObjCRuntimeObjectSectionsText
[] = {
257 MachOObjCClassNameSectionName
, MachOObjCMethNameSectionName
,
258 MachOObjCMethTypeSectionName
, MachOSwift5TypesSectionName
,
259 MachOSwift5TypeRefSectionName
, MachOSwift5FieldMetadataSectionName
,
260 MachOSwift5EntrySectionName
, MachOSwift5ProtoSectionName
,
261 MachOSwift5ProtosSectionName
};
263 static StringRef ObjCRuntimeObjectSectionName
=
264 "__llvm_jitlink_ObjCRuntimeRegistrationObject";
266 static StringRef ObjCImageInfoSymbolName
=
267 "__llvm_jitlink_macho_objc_imageinfo";
269 } // end anonymous namespace
274 Expected
<std::unique_ptr
<MachOPlatform
>>
275 MachOPlatform::Create(ExecutionSession
&ES
, ObjectLinkingLayer
&ObjLinkingLayer
,
276 JITDylib
&PlatformJD
,
277 std::unique_ptr
<DefinitionGenerator
> OrcRuntime
,
278 std::optional
<SymbolAliasMap
> RuntimeAliases
) {
280 // If the target is not supported then bail out immediately.
281 if (!supportedTarget(ES
.getTargetTriple()))
282 return make_error
<StringError
>("Unsupported MachOPlatform triple: " +
283 ES
.getTargetTriple().str(),
284 inconvertibleErrorCode());
286 auto &EPC
= ES
.getExecutorProcessControl();
288 // Create default aliases if the caller didn't supply any.
290 RuntimeAliases
= standardPlatformAliases(ES
);
292 // Define the aliases.
293 if (auto Err
= PlatformJD
.define(symbolAliases(std::move(*RuntimeAliases
))))
294 return std::move(Err
);
296 // Add JIT-dispatch function support symbols.
297 if (auto Err
= PlatformJD
.define(
298 absoluteSymbols({{ES
.intern("___orc_rt_jit_dispatch"),
299 {EPC
.getJITDispatchInfo().JITDispatchFunction
,
300 JITSymbolFlags::Exported
}},
301 {ES
.intern("___orc_rt_jit_dispatch_ctx"),
302 {EPC
.getJITDispatchInfo().JITDispatchContext
,
303 JITSymbolFlags::Exported
}}})))
304 return std::move(Err
);
306 // Create the instance.
307 Error Err
= Error::success();
308 auto P
= std::unique_ptr
<MachOPlatform
>(new MachOPlatform(
309 ES
, ObjLinkingLayer
, PlatformJD
, std::move(OrcRuntime
), Err
));
311 return std::move(Err
);
315 Expected
<std::unique_ptr
<MachOPlatform
>>
316 MachOPlatform::Create(ExecutionSession
&ES
, ObjectLinkingLayer
&ObjLinkingLayer
,
317 JITDylib
&PlatformJD
, const char *OrcRuntimePath
,
318 std::optional
<SymbolAliasMap
> RuntimeAliases
) {
320 // Create a generator for the ORC runtime archive.
321 auto OrcRuntimeArchiveGenerator
=
322 StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer
, OrcRuntimePath
);
323 if (!OrcRuntimeArchiveGenerator
)
324 return OrcRuntimeArchiveGenerator
.takeError();
326 return Create(ES
, ObjLinkingLayer
, PlatformJD
,
327 std::move(*OrcRuntimeArchiveGenerator
),
328 std::move(RuntimeAliases
));
331 Error
MachOPlatform::setupJITDylib(JITDylib
&JD
) {
332 if (auto Err
= JD
.define(std::make_unique
<MachOHeaderMaterializationUnit
>(
333 *this, MachOHeaderStartSymbol
)))
336 return ES
.lookup({&JD
}, MachOHeaderStartSymbol
).takeError();
339 Error
MachOPlatform::teardownJITDylib(JITDylib
&JD
) {
340 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
341 auto I
= JITDylibToHeaderAddr
.find(&JD
);
342 if (I
!= JITDylibToHeaderAddr
.end()) {
343 assert(HeaderAddrToJITDylib
.count(I
->second
) &&
344 "HeaderAddrToJITDylib missing entry");
345 HeaderAddrToJITDylib
.erase(I
->second
);
346 JITDylibToHeaderAddr
.erase(I
);
348 JITDylibToPThreadKey
.erase(&JD
);
349 return Error::success();
352 Error
MachOPlatform::notifyAdding(ResourceTracker
&RT
,
353 const MaterializationUnit
&MU
) {
354 auto &JD
= RT
.getJITDylib();
355 const auto &InitSym
= MU
.getInitializerSymbol();
357 return Error::success();
359 RegisteredInitSymbols
[&JD
].add(InitSym
,
360 SymbolLookupFlags::WeaklyReferencedSymbol
);
362 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym
<< " for MU "
363 << MU
.getName() << "\n";
365 return Error::success();
368 Error
MachOPlatform::notifyRemoving(ResourceTracker
&RT
) {
369 llvm_unreachable("Not supported yet");
372 static void addAliases(ExecutionSession
&ES
, SymbolAliasMap
&Aliases
,
373 ArrayRef
<std::pair
<const char *, const char *>> AL
) {
374 for (auto &KV
: AL
) {
375 auto AliasName
= ES
.intern(KV
.first
);
376 assert(!Aliases
.count(AliasName
) && "Duplicate symbol name in alias map");
377 Aliases
[std::move(AliasName
)] = {ES
.intern(KV
.second
),
378 JITSymbolFlags::Exported
};
382 SymbolAliasMap
MachOPlatform::standardPlatformAliases(ExecutionSession
&ES
) {
383 SymbolAliasMap Aliases
;
384 addAliases(ES
, Aliases
, requiredCXXAliases());
385 addAliases(ES
, Aliases
, standardRuntimeUtilityAliases());
389 ArrayRef
<std::pair
<const char *, const char *>>
390 MachOPlatform::requiredCXXAliases() {
391 static const std::pair
<const char *, const char *> RequiredCXXAliases
[] = {
392 {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
394 return ArrayRef
<std::pair
<const char *, const char *>>(RequiredCXXAliases
);
397 ArrayRef
<std::pair
<const char *, const char *>>
398 MachOPlatform::standardRuntimeUtilityAliases() {
399 static const std::pair
<const char *, const char *>
400 StandardRuntimeUtilityAliases
[] = {
401 {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
402 {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
403 {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
404 {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
405 {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
406 {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
408 return ArrayRef
<std::pair
<const char *, const char *>>(
409 StandardRuntimeUtilityAliases
);
412 bool MachOPlatform::supportedTarget(const Triple
&TT
) {
413 switch (TT
.getArch()) {
414 case Triple::aarch64
:
422 MachOPlatform::MachOPlatform(
423 ExecutionSession
&ES
, ObjectLinkingLayer
&ObjLinkingLayer
,
424 JITDylib
&PlatformJD
,
425 std::unique_ptr
<DefinitionGenerator
> OrcRuntimeGenerator
, Error
&Err
)
426 : ES(ES
), PlatformJD(PlatformJD
), ObjLinkingLayer(ObjLinkingLayer
) {
427 ErrorAsOutParameter
_(&Err
);
428 ObjLinkingLayer
.addPlugin(std::make_unique
<MachOPlatformPlugin
>(*this));
429 PlatformJD
.addGenerator(std::move(OrcRuntimeGenerator
));
434 // Bootstrap process -- here be phase-ordering dragons.
436 // The MachOPlatform class uses allocation actions to register metadata
437 // sections with the ORC runtime, however the runtime contains metadata
438 // registration functions that have their own metadata that they need to
439 // register (e.g. the frame-info registration functions have frame-info).
440 // We can't use an ordinary lookup to find these registration functions
441 // because their address is needed during the link of the containing graph
442 // itself (to build the allocation actions that will call the registration
443 // functions). Further complicating the situation (a) the graph containing
444 // the registration functions is allowed to depend on other graphs (e.g. the
445 // graph containing the ORC runtime RTTI support) so we need to handle with
446 // an unknown set of dependencies during bootstrap, and (b) these graphs may
447 // be linked concurrently if the user has installed a concurrent dispatcher.
449 // We satisfy these constraint by implementing a bootstrap phase during which
450 // allocation actions generated by MachOPlatform are appended to a list of
451 // deferred allocation actions, rather than to the graphs themselves. At the
452 // end of the bootstrap process the deferred actions are attached to a final
453 // "complete-bootstrap" graph that causes them to be run.
455 // The bootstrap steps are as follows:
457 // 1. Request the graph containing the mach header. This graph is guaranteed
458 // not to have any metadata so the fact that the registration functions
459 // are not available yet is not a problem.
461 // 2. Look up the registration functions and discard the results. This will
462 // trigger linking of the graph containing these functions, and
463 // consequently any graphs that it depends on. We do not use the lookup
464 // result to find the addresses of the functions requested (as described
465 // above the lookup will return too late for that), instead we capture the
466 // addresses in a post-allocation pass injected by the platform runtime
467 // during bootstrap only.
469 // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of
470 // graphs being linked (potentially concurrently), and we block until all
471 // of these graphs have completed linking. This is to avoid a race on the
472 // deferred-actions vector: the lookup for the runtime registration
473 // functions may return while some functions (those that are being
474 // incidentally linked in, but aren't reachable via the runtime functions)
475 // are still being linked, and we need to capture any allocation actions
476 // for this incidental code before we proceed.
478 // 4. Once all active links are complete we transfer the deferred actions to
479 // a newly added CompleteBootstrap graph and then request a symbol from
480 // the CompleteBootstrap graph to trigger materialization. This will cause
481 // all deferred actions to be run, and once this lookup returns we can
484 // 5. Finally, we associate runtime support methods in MachOPlatform with
485 // the corresponding jit-dispatch tag variables in the ORC runtime to make
486 // the support methods callable. The bootstrap is now complete.
488 // Step (1) Add header materialization unit and request.
489 if ((Err
= PlatformJD
.define(std::make_unique
<MachOHeaderMaterializationUnit
>(
490 *this, MachOHeaderStartSymbol
))))
492 if ((Err
= ES
.lookup(&PlatformJD
, MachOHeaderStartSymbol
).takeError()))
495 // Step (2) Request runtime registration functions to trigger
497 if ((Err
= ES
.lookup(makeJITDylibSearchOrder(&PlatformJD
),
499 {PlatformBootstrap
.Name
, PlatformShutdown
.Name
,
500 RegisterJITDylib
.Name
, DeregisterJITDylib
.Name
,
501 RegisterObjectPlatformSections
.Name
,
502 DeregisterObjectPlatformSections
.Name
,
503 CreatePThreadKey
.Name
}))
507 // Step (3) Wait for any incidental linker work to complete.
509 std::unique_lock
<std::mutex
> Lock(BI
.Mutex
);
510 BI
.CV
.wait(Lock
, [&]() { return BI
.ActiveGraphs
== 0; });
514 // Step (4) Add complete-bootstrap materialization unit and request.
515 auto BootstrapCompleteSymbol
= ES
.intern("__orc_rt_macho_complete_bootstrap");
516 if ((Err
= PlatformJD
.define(
517 std::make_unique
<MachOPlatformCompleteBootstrapMaterializationUnit
>(
518 *this, PlatformJD
.getName(), BootstrapCompleteSymbol
,
519 std::move(BI
.DeferredAAs
), PlatformBootstrap
.Addr
,
520 PlatformShutdown
.Addr
, RegisterJITDylib
.Addr
,
521 DeregisterJITDylib
.Addr
, BI
.MachOHeaderAddr
))))
523 if ((Err
= ES
.lookup(makeJITDylibSearchOrder(
524 &PlatformJD
, JITDylibLookupFlags::MatchAllSymbols
),
525 std::move(BootstrapCompleteSymbol
))
529 // (5) Associate runtime support functions.
530 if ((Err
= associateRuntimeSupportFunctions()))
534 Error
MachOPlatform::associateRuntimeSupportFunctions() {
535 ExecutionSession::JITDispatchHandlerAssociationMap WFs
;
537 using PushInitializersSPSSig
=
538 SPSExpected
<SPSMachOJITDylibDepInfoMap
>(SPSExecutorAddr
);
539 WFs
[ES
.intern("___orc_rt_macho_push_initializers_tag")] =
540 ES
.wrapAsyncWithSPS
<PushInitializersSPSSig
>(
541 this, &MachOPlatform::rt_pushInitializers
);
543 using LookupSymbolSPSSig
=
544 SPSExpected
<SPSExecutorAddr
>(SPSExecutorAddr
, SPSString
);
545 WFs
[ES
.intern("___orc_rt_macho_symbol_lookup_tag")] =
546 ES
.wrapAsyncWithSPS
<LookupSymbolSPSSig
>(this,
547 &MachOPlatform::rt_lookupSymbol
);
549 return ES
.registerJITDispatchHandlers(PlatformJD
, std::move(WFs
));
552 void MachOPlatform::pushInitializersLoop(
553 PushInitializersSendResultFn SendResult
, JITDylibSP JD
) {
554 DenseMap
<JITDylib
*, SymbolLookupSet
> NewInitSymbols
;
555 DenseMap
<JITDylib
*, SmallVector
<JITDylib
*>> JDDepMap
;
556 SmallVector
<JITDylib
*, 16> Worklist({JD
.get()});
558 ES
.runSessionLocked([&]() {
559 while (!Worklist
.empty()) {
560 // FIXME: Check for defunct dylibs.
562 auto DepJD
= Worklist
.back();
565 // If we've already visited this JITDylib on this iteration then continue.
566 if (JDDepMap
.count(DepJD
))
570 auto &DM
= JDDepMap
[DepJD
];
571 DepJD
->withLinkOrderDo([&](const JITDylibSearchOrder
&O
) {
573 if (KV
.first
== DepJD
)
575 DM
.push_back(KV
.first
);
576 Worklist
.push_back(KV
.first
);
580 // Add any registered init symbols.
581 auto RISItr
= RegisteredInitSymbols
.find(DepJD
);
582 if (RISItr
!= RegisteredInitSymbols
.end()) {
583 NewInitSymbols
[DepJD
] = std::move(RISItr
->second
);
584 RegisteredInitSymbols
.erase(RISItr
);
589 // If there are no further init symbols to look up then send the link order
590 // (as a list of header addresses) to the caller.
591 if (NewInitSymbols
.empty()) {
593 // To make the list intelligible to the runtime we need to convert all
594 // JITDylib pointers to their header addresses. Only include JITDylibs
595 // that appear in the JITDylibToHeaderAddr map (i.e. those that have been
596 // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
597 DenseMap
<JITDylib
*, ExecutorAddr
> HeaderAddrs
;
598 HeaderAddrs
.reserve(JDDepMap
.size());
600 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
601 for (auto &KV
: JDDepMap
) {
602 auto I
= JITDylibToHeaderAddr
.find(KV
.first
);
603 if (I
!= JITDylibToHeaderAddr
.end())
604 HeaderAddrs
[KV
.first
] = I
->second
;
608 // Build the dep info map to return.
609 MachOJITDylibDepInfoMap DIM
;
610 DIM
.reserve(JDDepMap
.size());
611 for (auto &KV
: JDDepMap
) {
612 auto HI
= HeaderAddrs
.find(KV
.first
);
613 // Skip unmanaged JITDylibs.
614 if (HI
== HeaderAddrs
.end())
617 MachOJITDylibDepInfo DepInfo
;
618 for (auto &Dep
: KV
.second
) {
619 auto HJ
= HeaderAddrs
.find(Dep
);
620 if (HJ
!= HeaderAddrs
.end())
621 DepInfo
.DepHeaders
.push_back(HJ
->second
);
623 DIM
.push_back(std::make_pair(H
, std::move(DepInfo
)));
629 // Otherwise issue a lookup and re-run this phase when it completes.
630 lookupInitSymbolsAsync(
631 [this, SendResult
= std::move(SendResult
), JD
](Error Err
) mutable {
633 SendResult(std::move(Err
));
635 pushInitializersLoop(std::move(SendResult
), JD
);
637 ES
, std::move(NewInitSymbols
));
640 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult
,
641 ExecutorAddr JDHeaderAddr
) {
644 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
645 auto I
= HeaderAddrToJITDylib
.find(JDHeaderAddr
);
646 if (I
!= HeaderAddrToJITDylib
.end())
651 dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr
<< ") ";
653 dbgs() << "pushing initializers for " << JD
->getName() << "\n";
655 dbgs() << "No JITDylib for header address.\n";
659 SendResult(make_error
<StringError
>("No JITDylib with header addr " +
660 formatv("{0:x}", JDHeaderAddr
),
661 inconvertibleErrorCode()));
665 pushInitializersLoop(std::move(SendResult
), JD
);
668 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult
,
669 ExecutorAddr Handle
, StringRef SymbolName
) {
671 dbgs() << "MachOPlatform::rt_lookupSymbol(\"" << Handle
<< "\")\n";
674 JITDylib
*JD
= nullptr;
677 std::lock_guard
<std::mutex
> Lock(PlatformMutex
);
678 auto I
= HeaderAddrToJITDylib
.find(Handle
);
679 if (I
!= HeaderAddrToJITDylib
.end())
684 LLVM_DEBUG(dbgs() << " No JITDylib for handle " << Handle
<< "\n");
685 SendResult(make_error
<StringError
>("No JITDylib associated with handle " +
686 formatv("{0:x}", Handle
),
687 inconvertibleErrorCode()));
691 // Use functor class to work around XL build compiler issue on AIX.
692 class RtLookupNotifyComplete
{
694 RtLookupNotifyComplete(SendSymbolAddressFn
&&SendResult
)
695 : SendResult(std::move(SendResult
)) {}
696 void operator()(Expected
<SymbolMap
> Result
) {
698 assert(Result
->size() == 1 && "Unexpected result map count");
699 SendResult(Result
->begin()->second
.getAddress());
701 SendResult(Result
.takeError());
706 SendSymbolAddressFn SendResult
;
709 // FIXME: Proper mangling.
710 auto MangledName
= ("_" + SymbolName
).str();
712 LookupKind::DLSym
, {{JD
, JITDylibLookupFlags::MatchExportedSymbolsOnly
}},
713 SymbolLookupSet(ES
.intern(MangledName
)), SymbolState::Ready
,
714 RtLookupNotifyComplete(std::move(SendResult
)), NoDependenciesToRegister
);
717 Expected
<uint64_t> MachOPlatform::createPThreadKey() {
718 if (!CreatePThreadKey
.Addr
)
719 return make_error
<StringError
>(
720 "Attempting to create pthread key in target, but runtime support has "
721 "not been loaded yet",
722 inconvertibleErrorCode());
724 Expected
<uint64_t> Result(0);
725 if (auto Err
= ES
.callSPSWrapper
<SPSExpected
<uint64_t>(void)>(
726 CreatePThreadKey
.Addr
, Result
))
727 return std::move(Err
);
731 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
732 MaterializationResponsibility
&MR
, jitlink::LinkGraph
&LG
,
733 jitlink::PassConfiguration
&Config
) {
735 using namespace jitlink
;
737 bool InBootstrapPhase
=
738 &MR
.getTargetJITDylib() == &MP
.PlatformJD
&& MP
.Bootstrap
;
740 // If we're in the bootstrap phase then increment the active graphs.
741 if (InBootstrapPhase
) {
742 Config
.PrePrunePasses
.push_back(
743 [this](LinkGraph
&G
) { return bootstrapPipelineStart(G
); });
744 Config
.PostAllocationPasses
.push_back([this](LinkGraph
&G
) {
745 return bootstrapPipelineRecordRuntimeFunctions(G
);
749 // --- Handle Initializers ---
750 if (auto InitSymbol
= MR
.getInitializerSymbol()) {
752 // If the initializer symbol is the MachOHeader start symbol then just
753 // register it and then bail out -- the header materialization unit
754 // definitely doesn't need any other passes.
755 if (InitSymbol
== MP
.MachOHeaderStartSymbol
&& !InBootstrapPhase
) {
756 Config
.PostAllocationPasses
.push_back([this, &MR
](LinkGraph
&G
) {
757 return associateJITDylibHeaderSymbol(G
, MR
);
762 // If the object contains an init symbol other than the header start symbol
763 // then add passes to preserve, process and register the init
765 Config
.PrePrunePasses
.push_back([this, &MR
](LinkGraph
&G
) {
766 if (auto Err
= preserveImportantSections(G
, MR
))
768 return processObjCImageInfo(G
, MR
);
770 Config
.PostPrunePasses
.push_back(
771 [this](LinkGraph
&G
) { return createObjCRuntimeObject(G
); });
772 Config
.PostAllocationPasses
.push_back(
773 [this, &MR
](LinkGraph
&G
) { return populateObjCRuntimeObject(G
, MR
); });
776 // Insert TLV lowering at the start of the PostPrunePasses, since we want
777 // it to run before GOT/PLT lowering.
778 Config
.PostPrunePasses
.insert(
779 Config
.PostPrunePasses
.begin(),
780 [this, &JD
= MR
.getTargetJITDylib()](LinkGraph
&G
) {
781 return fixTLVSectionsAndEdges(G
, JD
);
784 // Add a pass to register the final addresses of any special sections in the
785 // object with the runtime.
786 Config
.PostAllocationPasses
.push_back(
787 [this, &JD
= MR
.getTargetJITDylib(), InBootstrapPhase
](LinkGraph
&G
) {
788 return registerObjectPlatformSections(G
, JD
, InBootstrapPhase
);
791 // If we're in the bootstrap phase then steal allocation actions and then
792 // decrement the active graphs.
793 if (InBootstrapPhase
)
794 Config
.PostFixupPasses
.push_back(
795 [this](LinkGraph
&G
) { return bootstrapPipelineEnd(G
); });
798 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
799 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
800 MaterializationResponsibility
&MR
) {
801 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
802 auto I
= InitSymbolDeps
.find(&MR
);
803 if (I
!= InitSymbolDeps
.end()) {
804 SyntheticSymbolDependenciesMap Result
;
805 Result
[MR
.getInitializerSymbol()] = std::move(I
->second
);
806 InitSymbolDeps
.erase(&MR
);
809 return SyntheticSymbolDependenciesMap();
812 Error
MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart(
813 jitlink::LinkGraph
&G
) {
814 // Increment the active graphs count in BootstrapInfo.
815 std::lock_guard
<std::mutex
> Lock(MP
.Bootstrap
.load()->Mutex
);
816 ++MP
.Bootstrap
.load()->ActiveGraphs
;
817 return Error::success();
820 Error
MachOPlatform::MachOPlatformPlugin::
821 bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph
&G
) {
822 // Record bootstrap function names.
823 std::pair
<StringRef
, ExecutorAddr
*> RuntimeSymbols
[] = {
824 {*MP
.MachOHeaderStartSymbol
, &MP
.Bootstrap
.load()->MachOHeaderAddr
},
825 {*MP
.PlatformBootstrap
.Name
, &MP
.PlatformBootstrap
.Addr
},
826 {*MP
.PlatformShutdown
.Name
, &MP
.PlatformShutdown
.Addr
},
827 {*MP
.RegisterJITDylib
.Name
, &MP
.RegisterJITDylib
.Addr
},
828 {*MP
.DeregisterJITDylib
.Name
, &MP
.DeregisterJITDylib
.Addr
},
829 {*MP
.RegisterObjectPlatformSections
.Name
,
830 &MP
.RegisterObjectPlatformSections
.Addr
},
831 {*MP
.DeregisterObjectPlatformSections
.Name
,
832 &MP
.DeregisterObjectPlatformSections
.Addr
},
833 {*MP
.CreatePThreadKey
.Name
, &MP
.CreatePThreadKey
.Addr
},
834 {*MP
.RegisterObjCRuntimeObject
.Name
, &MP
.RegisterObjCRuntimeObject
.Addr
},
835 {*MP
.DeregisterObjCRuntimeObject
.Name
,
836 &MP
.DeregisterObjCRuntimeObject
.Addr
}};
838 bool RegisterMachOHeader
= false;
840 for (auto *Sym
: G
.defined_symbols()) {
841 for (auto &RTSym
: RuntimeSymbols
) {
842 if (Sym
->hasName() && Sym
->getName() == RTSym
.first
) {
844 return make_error
<StringError
>(
845 "Duplicate " + RTSym
.first
+
846 " detected during MachOPlatform bootstrap",
847 inconvertibleErrorCode());
849 if (Sym
->getName() == *MP
.MachOHeaderStartSymbol
)
850 RegisterMachOHeader
= true;
852 *RTSym
.second
= Sym
->getAddress();
857 if (RegisterMachOHeader
) {
858 // If this graph defines the macho header symbol then create the internal
859 // mapping between it and PlatformJD.
860 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
861 MP
.JITDylibToHeaderAddr
[&MP
.PlatformJD
] =
862 MP
.Bootstrap
.load()->MachOHeaderAddr
;
863 MP
.HeaderAddrToJITDylib
[MP
.Bootstrap
.load()->MachOHeaderAddr
] =
867 return Error::success();
870 Error
MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
871 jitlink::LinkGraph
&G
) {
872 std::lock_guard
<std::mutex
> Lock(MP
.Bootstrap
.load()->Mutex
);
873 assert(MP
.Bootstrap
&& "DeferredAAs reset before bootstrap completed");
874 --MP
.Bootstrap
.load()->ActiveGraphs
;
875 // Notify Bootstrap->CV while holding the mutex because the mutex is
876 // also keeping Bootstrap->CV alive.
877 if (MP
.Bootstrap
.load()->ActiveGraphs
== 0)
878 MP
.Bootstrap
.load()->CV
.notify_all();
879 return Error::success();
882 Error
MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
883 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
884 auto I
= llvm::find_if(G
.defined_symbols(), [this](jitlink::Symbol
*Sym
) {
885 return Sym
->getName() == *MP
.MachOHeaderStartSymbol
;
887 assert(I
!= G
.defined_symbols().end() && "Missing MachO header start symbol");
889 auto &JD
= MR
.getTargetJITDylib();
890 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
891 auto HeaderAddr
= (*I
)->getAddress();
892 MP
.JITDylibToHeaderAddr
[&JD
] = HeaderAddr
;
893 MP
.HeaderAddrToJITDylib
[HeaderAddr
] = &JD
;
894 // We can unconditionally add these actions to the Graph because this pass
895 // isn't used during bootstrap.
896 G
.allocActions().push_back(
898 WrapperFunctionCall::Create
<SPSArgList
<SPSString
, SPSExecutorAddr
>>(
899 MP
.RegisterJITDylib
.Addr
, JD
.getName(), HeaderAddr
)),
900 cantFail(WrapperFunctionCall::Create
<SPSArgList
<SPSExecutorAddr
>>(
901 MP
.DeregisterJITDylib
.Addr
, HeaderAddr
))});
902 return Error::success();
905 Error
MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
906 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
907 // __objc_imageinfo is "important": we want to preserve it and record its
908 // address in the first graph that it appears in, then verify and discard it
909 // in all subsequent graphs. In this pass we preserve unconditionally -- we'll
910 // manually throw it away in the processObjCImageInfo pass.
911 if (auto *ObjCImageInfoSec
=
912 G
.findSectionByName(MachOObjCImageInfoSectionName
)) {
913 if (ObjCImageInfoSec
->blocks_size() != 1)
914 return make_error
<StringError
>(
915 "In " + G
.getName() +
916 "__DATA,__objc_imageinfo contains multiple blocks",
917 inconvertibleErrorCode());
918 G
.addAnonymousSymbol(**ObjCImageInfoSec
->blocks().begin(), 0, 0, false,
921 for (auto *B
: ObjCImageInfoSec
->blocks())
922 if (!B
->edges_empty())
923 return make_error
<StringError
>("In " + G
.getName() + ", " +
924 MachOObjCImageInfoSectionName
+
925 " contains references to symbols",
926 inconvertibleErrorCode());
929 // Init sections are important: We need to preserve them and so that their
930 // addresses can be captured and reported to the ORC runtime in
931 // registerObjectPlatformSections.
932 JITLinkSymbolSet InitSectionSymbols
;
933 for (auto &InitSectionName
: MachOInitSectionNames
) {
934 // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may
936 if (InitSectionName
== MachOObjCImageInfoSectionName
)
939 // Skip non-init sections.
940 auto *InitSection
= G
.findSectionByName(InitSectionName
);
944 // Make a pass over live symbols in the section: those blocks are already
946 DenseSet
<jitlink::Block
*> AlreadyLiveBlocks
;
947 for (auto &Sym
: InitSection
->symbols()) {
948 auto &B
= Sym
->getBlock();
949 if (Sym
->isLive() && Sym
->getOffset() == 0 &&
950 Sym
->getSize() == B
.getSize() && !AlreadyLiveBlocks
.count(&B
)) {
951 InitSectionSymbols
.insert(Sym
);
952 AlreadyLiveBlocks
.insert(&B
);
956 // Add anonymous symbols to preserve any not-already-preserved blocks.
957 for (auto *B
: InitSection
->blocks())
958 if (!AlreadyLiveBlocks
.count(B
))
959 InitSectionSymbols
.insert(
960 &G
.addAnonymousSymbol(*B
, 0, B
->getSize(), false, true));
963 if (!InitSectionSymbols
.empty()) {
964 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
965 InitSymbolDeps
[&MR
] = std::move(InitSectionSymbols
);
968 return Error::success();
971 Error
MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
972 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
974 // If there's an ObjC imagine info then either
975 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
976 // this case we name and record it.
978 // (2) We already have a recorded __objc_imageinfo for this JITDylib,
979 // in which case we just verify it.
980 auto *ObjCImageInfo
= G
.findSectionByName(MachOObjCImageInfoSectionName
);
982 return Error::success();
984 auto ObjCImageInfoBlocks
= ObjCImageInfo
->blocks();
986 // Check that the section is not empty if present.
987 if (ObjCImageInfoBlocks
.empty())
988 return make_error
<StringError
>("Empty " + MachOObjCImageInfoSectionName
+
989 " section in " + G
.getName(),
990 inconvertibleErrorCode());
992 // Check that there's only one block in the section.
993 if (std::next(ObjCImageInfoBlocks
.begin()) != ObjCImageInfoBlocks
.end())
994 return make_error
<StringError
>("Multiple blocks in " +
995 MachOObjCImageInfoSectionName
+
996 " section in " + G
.getName(),
997 inconvertibleErrorCode());
999 // Check that the __objc_imageinfo section is unreferenced.
1000 // FIXME: We could optimize this check if Symbols had a ref-count.
1001 for (auto &Sec
: G
.sections()) {
1002 if (&Sec
!= ObjCImageInfo
)
1003 for (auto *B
: Sec
.blocks())
1004 for (auto &E
: B
->edges())
1005 if (E
.getTarget().isDefined() &&
1006 &E
.getTarget().getBlock().getSection() == ObjCImageInfo
)
1007 return make_error
<StringError
>(MachOObjCImageInfoSectionName
+
1008 " is referenced within file " +
1010 inconvertibleErrorCode());
1013 auto &ObjCImageInfoBlock
= **ObjCImageInfoBlocks
.begin();
1014 auto *ObjCImageInfoData
= ObjCImageInfoBlock
.getContent().data();
1015 auto Version
= support::endian::read32(ObjCImageInfoData
, G
.getEndianness());
1017 support::endian::read32(ObjCImageInfoData
+ 4, G
.getEndianness());
1019 // Lock the mutex while we verify / update the ObjCImageInfos map.
1020 std::lock_guard
<std::mutex
> Lock(PluginMutex
);
1022 auto ObjCImageInfoItr
= ObjCImageInfos
.find(&MR
.getTargetJITDylib());
1023 if (ObjCImageInfoItr
!= ObjCImageInfos
.end()) {
1024 // We've already registered an __objc_imageinfo section. Verify the
1025 // content of this new section matches, then delete it.
1026 if (ObjCImageInfoItr
->second
.Version
!= Version
)
1027 return make_error
<StringError
>(
1028 "ObjC version in " + G
.getName() +
1029 " does not match first registered version",
1030 inconvertibleErrorCode());
1031 if (ObjCImageInfoItr
->second
.Flags
!= Flags
)
1032 return make_error
<StringError
>("ObjC flags in " + G
.getName() +
1033 " do not match first registered flags",
1034 inconvertibleErrorCode());
1036 // __objc_imageinfo is valid. Delete the block.
1037 for (auto *S
: ObjCImageInfo
->symbols())
1038 G
.removeDefinedSymbol(*S
);
1039 G
.removeBlock(ObjCImageInfoBlock
);
1041 // We haven't registered an __objc_imageinfo section yet. Register and
1042 // move on. The section should already be marked no-dead-strip.
1043 G
.addDefinedSymbol(ObjCImageInfoBlock
, 0, ObjCImageInfoSymbolName
,
1044 ObjCImageInfoBlock
.getSize(), jitlink::Linkage::Strong
,
1045 jitlink::Scope::Hidden
, false, true);
1046 if (auto Err
= MR
.defineMaterializing(
1047 {{MR
.getExecutionSession().intern(ObjCImageInfoSymbolName
),
1048 JITSymbolFlags()}}))
1050 ObjCImageInfos
[&MR
.getTargetJITDylib()] = {Version
, Flags
};
1053 return Error::success();
1056 Error
MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1057 jitlink::LinkGraph
&G
, JITDylib
&JD
) {
1059 // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
1060 for (auto *Sym
: G
.external_symbols())
1061 if (Sym
->getName() == "__tlv_bootstrap") {
1062 Sym
->setName("___orc_rt_macho_tlv_get_addr");
1066 // Store key in __thread_vars struct fields.
1067 if (auto *ThreadDataSec
= G
.findSectionByName(MachOThreadVarsSectionName
)) {
1068 std::optional
<uint64_t> Key
;
1070 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
1071 auto I
= MP
.JITDylibToPThreadKey
.find(&JD
);
1072 if (I
!= MP
.JITDylibToPThreadKey
.end())
1077 if (auto KeyOrErr
= MP
.createPThreadKey())
1080 return KeyOrErr
.takeError();
1083 uint64_t PlatformKeyBits
=
1084 support::endian::byte_swap(*Key
, G
.getEndianness());
1086 for (auto *B
: ThreadDataSec
->blocks()) {
1087 if (B
->getSize() != 3 * G
.getPointerSize())
1088 return make_error
<StringError
>("__thread_vars block at " +
1089 formatv("{0:x}", B
->getAddress()) +
1090 " has unexpected size",
1091 inconvertibleErrorCode());
1093 auto NewBlockContent
= G
.allocateBuffer(B
->getSize());
1094 llvm::copy(B
->getContent(), NewBlockContent
.data());
1095 memcpy(NewBlockContent
.data() + G
.getPointerSize(), &PlatformKeyBits
,
1096 G
.getPointerSize());
1097 B
->setContent(NewBlockContent
);
1101 // Transform any TLV edges into GOT edges.
1102 for (auto *B
: G
.blocks())
1103 for (auto &E
: B
->edges())
1105 jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
)
1106 E
.setKind(jitlink::x86_64::
1107 RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable
);
1109 return Error::success();
1112 std::optional
<MachOPlatform::MachOPlatformPlugin::UnwindSections
>
1113 MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1114 jitlink::LinkGraph
&G
) {
1115 using namespace jitlink
;
1119 // ScanSection records a section range and adds any executable blocks that
1120 // that section points to to the CodeBlocks vector.
1121 SmallVector
<Block
*> CodeBlocks
;
1122 auto ScanUnwindInfoSection
= [&](Section
&Sec
, ExecutorAddrRange
&SecRange
) {
1123 if (Sec
.blocks().empty())
1125 SecRange
= (*Sec
.blocks().begin())->getRange();
1126 for (auto *B
: Sec
.blocks()) {
1127 auto R
= B
->getRange();
1128 SecRange
.Start
= std::min(SecRange
.Start
, R
.Start
);
1129 SecRange
.End
= std::max(SecRange
.End
, R
.End
);
1130 for (auto &E
: B
->edges()) {
1131 if (!E
.getTarget().isDefined())
1133 auto &TargetBlock
= E
.getTarget().getBlock();
1134 auto &TargetSection
= TargetBlock
.getSection();
1135 if ((TargetSection
.getMemProt() & MemProt::Exec
) == MemProt::Exec
)
1136 CodeBlocks
.push_back(&TargetBlock
);
1141 if (Section
*EHFrameSec
= G
.findSectionByName(MachOEHFrameSectionName
))
1142 ScanUnwindInfoSection(*EHFrameSec
, US
.DwarfSection
);
1144 if (Section
*CUInfoSec
=
1145 G
.findSectionByName(MachOCompactUnwindInfoSectionName
))
1146 ScanUnwindInfoSection(*CUInfoSec
, US
.CompactUnwindSection
);
1148 // If we didn't find any pointed-to code-blocks then there's no need to
1149 // register any info.
1150 if (CodeBlocks
.empty())
1151 return std::nullopt
;
1153 // We have info to register. Sort the code blocks into address order and
1154 // build a list of contiguous address ranges covering them all.
1155 llvm::sort(CodeBlocks
, [](const Block
*LHS
, const Block
*RHS
) {
1156 return LHS
->getAddress() < RHS
->getAddress();
1158 for (auto *B
: CodeBlocks
) {
1159 if (US
.CodeRanges
.empty() || US
.CodeRanges
.back().End
!= B
->getAddress())
1160 US
.CodeRanges
.push_back(B
->getRange());
1162 US
.CodeRanges
.back().End
= B
->getRange().End
;
1166 dbgs() << "MachOPlatform identified unwind info in " << G
.getName() << ":\n"
1168 if (US
.DwarfSection
.Start
)
1169 dbgs() << US
.DwarfSection
<< "\n";
1172 dbgs() << " Compact-unwind: ";
1173 if (US
.CompactUnwindSection
.Start
)
1174 dbgs() << US
.CompactUnwindSection
<< "\n";
1177 << "for code ranges:\n";
1178 for (auto &CR
: US
.CodeRanges
)
1179 dbgs() << " " << CR
<< "\n";
1180 if (US
.CodeRanges
.size() >= G
.sections_size())
1181 dbgs() << "WARNING: High number of discontiguous code ranges! "
1182 "Padding may be interfering with coalescing.\n";
1188 Error
MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1189 jitlink::LinkGraph
&G
, JITDylib
&JD
, bool InBootstrapPhase
) {
1191 // Get a pointer to the thread data section if there is one. It will be used
1193 jitlink::Section
*ThreadDataSection
=
1194 G
.findSectionByName(MachOThreadDataSectionName
);
1196 // Handle thread BSS section if there is one.
1197 if (auto *ThreadBSSSection
= G
.findSectionByName(MachOThreadBSSSectionName
)) {
1198 // If there's already a thread data section in this graph then merge the
1199 // thread BSS section content into it, otherwise just treat the thread
1200 // BSS section as the thread data section.
1201 if (ThreadDataSection
)
1202 G
.mergeSections(*ThreadDataSection
, *ThreadBSSSection
);
1204 ThreadDataSection
= ThreadBSSSection
;
1207 SmallVector
<std::pair
<StringRef
, ExecutorAddrRange
>, 8> MachOPlatformSecs
;
1209 // Collect data sections to register.
1210 StringRef DataSections
[] = {MachODataDataSectionName
,
1211 MachODataCommonSectionName
,
1212 MachOEHFrameSectionName
};
1213 for (auto &SecName
: DataSections
) {
1214 if (auto *Sec
= G
.findSectionByName(SecName
)) {
1215 jitlink::SectionRange
R(*Sec
);
1217 MachOPlatformSecs
.push_back({SecName
, R
.getRange()});
1221 // Having merged thread BSS (if present) and thread data (if present),
1222 // record the resulting section range.
1223 if (ThreadDataSection
) {
1224 jitlink::SectionRange
R(*ThreadDataSection
);
1226 MachOPlatformSecs
.push_back({MachOThreadDataSectionName
, R
.getRange()});
1229 // If any platform sections were found then add an allocation action to call
1230 // the registration function.
1231 StringRef PlatformSections
[] = {MachOModInitFuncSectionName
,
1232 ObjCRuntimeObjectSectionName
};
1234 for (auto &SecName
: PlatformSections
) {
1235 auto *Sec
= G
.findSectionByName(SecName
);
1238 jitlink::SectionRange
R(*Sec
);
1242 MachOPlatformSecs
.push_back({SecName
, R
.getRange()});
1245 std::optional
<std::tuple
<SmallVector
<ExecutorAddrRange
>, ExecutorAddrRange
,
1248 if (auto UI
= findUnwindSectionInfo(G
))
1249 UnwindInfo
= std::make_tuple(std::move(UI
->CodeRanges
), UI
->DwarfSection
,
1250 UI
->CompactUnwindSection
);
1252 if (!MachOPlatformSecs
.empty() || UnwindInfo
) {
1253 ExecutorAddr HeaderAddr
;
1255 std::lock_guard
<std::mutex
> Lock(MP
.PlatformMutex
);
1256 auto I
= MP
.JITDylibToHeaderAddr
.find(&JD
);
1257 assert(I
!= MP
.JITDylibToHeaderAddr
.end() &&
1258 "Missing header for JITDylib");
1259 HeaderAddr
= I
->second
;
1262 // Dump the scraped inits.
1264 dbgs() << "MachOPlatform: Scraped " << G
.getName() << " init sections:\n";
1265 for (auto &KV
: MachOPlatformSecs
)
1266 dbgs() << " " << KV
.first
<< ": " << KV
.second
<< "\n";
1269 using SPSRegisterObjectPlatformSectionsArgs
= SPSArgList
<
1271 SPSOptional
<SPSTuple
<SPSSequence
<SPSExecutorAddrRange
>,
1272 SPSExecutorAddrRange
, SPSExecutorAddrRange
>>,
1273 SPSSequence
<SPSTuple
<SPSString
, SPSExecutorAddrRange
>>>;
1275 shared::AllocActions
&allocActions
= LLVM_LIKELY(!InBootstrapPhase
)
1277 : MP
.Bootstrap
.load()->DeferredAAs
;
1279 allocActions
.push_back(
1281 WrapperFunctionCall::Create
<SPSRegisterObjectPlatformSectionsArgs
>(
1282 MP
.RegisterObjectPlatformSections
.Addr
, HeaderAddr
, UnwindInfo
,
1283 MachOPlatformSecs
)),
1285 WrapperFunctionCall::Create
<SPSRegisterObjectPlatformSectionsArgs
>(
1286 MP
.DeregisterObjectPlatformSections
.Addr
, HeaderAddr
,
1287 UnwindInfo
, MachOPlatformSecs
))});
1290 return Error::success();
1293 Error
MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
1294 jitlink::LinkGraph
&G
) {
1296 bool NeedTextSegment
= false;
1297 size_t NumRuntimeSections
= 0;
1299 for (auto ObjCRuntimeSectionName
: ObjCRuntimeObjectSectionsData
)
1300 if (G
.findSectionByName(ObjCRuntimeSectionName
))
1301 ++NumRuntimeSections
;
1303 for (auto ObjCRuntimeSectionName
: ObjCRuntimeObjectSectionsText
) {
1304 if (G
.findSectionByName(ObjCRuntimeSectionName
)) {
1305 ++NumRuntimeSections
;
1306 NeedTextSegment
= true;
1310 // Early out for no runtime sections.
1311 if (NumRuntimeSections
== 0)
1312 return Error::success();
1314 // If there were any runtime sections then we need to add an __objc_imageinfo
1316 ++NumRuntimeSections
;
1318 size_t MachOSize
= sizeof(MachO::mach_header_64
) +
1319 (NeedTextSegment
+ 1) * sizeof(MachO::segment_command_64
) +
1320 NumRuntimeSections
* sizeof(MachO::section_64
);
1322 auto &Sec
= G
.createSection(ObjCRuntimeObjectSectionName
,
1323 MemProt::Read
| MemProt::Write
);
1324 G
.createMutableContentBlock(Sec
, MachOSize
, ExecutorAddr(), 16, 0, true);
1326 return Error::success();
1329 Error
MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
1330 jitlink::LinkGraph
&G
, MaterializationResponsibility
&MR
) {
1332 auto *ObjCRuntimeObjectSec
=
1333 G
.findSectionByName(ObjCRuntimeObjectSectionName
);
1335 if (!ObjCRuntimeObjectSec
)
1336 return Error::success();
1338 switch (G
.getTargetTriple().getArch()) {
1339 case Triple::aarch64
:
1340 case Triple::x86_64
:
1344 return make_error
<StringError
>("Unrecognized MachO arch in triple " +
1345 G
.getTargetTriple().str(),
1346 inconvertibleErrorCode());
1349 auto &SecBlock
= **ObjCRuntimeObjectSec
->blocks().begin();
1352 MachO::section_64 Sec
;
1353 unique_function
<void(size_t RecordOffset
)> AddFixups
;
1356 std::vector
<SecDesc
> TextSections
, DataSections
;
1357 auto AddSection
= [&](SecDesc
&SD
, jitlink::Section
&GraphSec
) {
1358 jitlink::SectionRange
SR(GraphSec
);
1359 StringRef FQName
= GraphSec
.getName();
1360 memset(&SD
.Sec
, 0, sizeof(MachO::section_64
));
1361 memcpy(SD
.Sec
.sectname
, FQName
.drop_front(7).data(), FQName
.size() - 7);
1362 memcpy(SD
.Sec
.segname
, FQName
.data(), 6);
1363 SD
.Sec
.addr
= SR
.getStart() - SecBlock
.getAddress();
1364 SD
.Sec
.size
= SR
.getSize();
1365 SD
.Sec
.flags
= MachO::S_REGULAR
;
1368 // Add the __objc_imageinfo section.
1370 DataSections
.push_back({});
1371 auto &SD
= DataSections
.back();
1372 memset(&SD
.Sec
, 0, sizeof(SD
.Sec
));
1373 memcpy(SD
.Sec
.sectname
, "__objc_imageinfo", 16);
1374 strcpy(SD
.Sec
.segname
, "__DATA");
1376 SD
.AddFixups
= [&](size_t RecordOffset
) {
1377 jitlink::Edge::Kind PointerEdge
= jitlink::Edge::Invalid
;
1378 switch (G
.getTargetTriple().getArch()) {
1379 case Triple::aarch64
:
1380 PointerEdge
= jitlink::aarch64::Pointer64
;
1382 case Triple::x86_64
:
1383 PointerEdge
= jitlink::x86_64::Pointer64
;
1386 llvm_unreachable("Unsupported architecture");
1389 // Look for an existing __objc_imageinfo symbol.
1390 jitlink::Symbol
*ObjCImageInfoSym
= nullptr;
1391 for (auto *Sym
: G
.external_symbols())
1392 if (Sym
->getName() == ObjCImageInfoSymbolName
) {
1393 ObjCImageInfoSym
= Sym
;
1396 if (!ObjCImageInfoSym
)
1397 for (auto *Sym
: G
.absolute_symbols())
1398 if (Sym
->getName() == ObjCImageInfoSymbolName
) {
1399 ObjCImageInfoSym
= Sym
;
1402 if (!ObjCImageInfoSym
)
1403 for (auto *Sym
: G
.defined_symbols())
1404 if (Sym
->hasName() && Sym
->getName() == ObjCImageInfoSymbolName
) {
1405 ObjCImageInfoSym
= Sym
;
1408 if (!ObjCImageInfoSym
)
1410 &G
.addExternalSymbol(ObjCImageInfoSymbolName
, 8, false);
1412 SecBlock
.addEdge(PointerEdge
,
1413 RecordOffset
+ ((char *)&SD
.Sec
.addr
- (char *)&SD
.Sec
),
1414 *ObjCImageInfoSym
, -SecBlock
.getAddress().getValue());
1418 for (auto ObjCRuntimeSectionName
: ObjCRuntimeObjectSectionsData
) {
1419 if (auto *GraphSec
= G
.findSectionByName(ObjCRuntimeSectionName
)) {
1420 DataSections
.push_back({});
1421 AddSection(DataSections
.back(), *GraphSec
);
1425 for (auto ObjCRuntimeSectionName
: ObjCRuntimeObjectSectionsText
) {
1426 if (auto *GraphSec
= G
.findSectionByName(ObjCRuntimeSectionName
)) {
1427 TextSections
.push_back({});
1428 AddSection(TextSections
.back(), *GraphSec
);
1432 assert(ObjCRuntimeObjectSec
->blocks_size() == 1 &&
1433 "Unexpected number of blocks in runtime sections object");
1435 // Build the header struct up-front. This also gives us a chance to check
1436 // that the triple is supported, which we'll assume below.
1437 MachO::mach_header_64 Hdr
;
1438 Hdr
.magic
= MachO::MH_MAGIC_64
;
1439 switch (G
.getTargetTriple().getArch()) {
1440 case Triple::aarch64
:
1441 Hdr
.cputype
= MachO::CPU_TYPE_ARM64
;
1442 Hdr
.cpusubtype
= MachO::CPU_SUBTYPE_ARM64_ALL
;
1444 case Triple::x86_64
:
1445 Hdr
.cputype
= MachO::CPU_TYPE_X86_64
;
1446 Hdr
.cpusubtype
= MachO::CPU_SUBTYPE_X86_64_ALL
;
1449 llvm_unreachable("Unsupported architecture");
1452 Hdr
.filetype
= MachO::MH_DYLIB
;
1453 Hdr
.ncmds
= 1 + !TextSections
.empty();
1455 Hdr
.ncmds
* sizeof(MachO::segment_command_64
) +
1456 (TextSections
.size() + DataSections
.size()) * sizeof(MachO::section_64
);
1460 auto SecContent
= SecBlock
.getAlreadyMutableContent();
1461 char *P
= SecContent
.data();
1462 auto WriteMachOStruct
= [&](auto S
) {
1463 if (G
.getEndianness() != llvm::endianness::native
)
1464 MachO::swapStruct(S
);
1465 memcpy(P
, &S
, sizeof(S
));
1469 auto WriteSegment
= [&](StringRef Name
, std::vector
<SecDesc
> &Secs
) {
1470 MachO::segment_command_64 SegLC
;
1471 memset(&SegLC
, 0, sizeof(SegLC
));
1472 memcpy(SegLC
.segname
, Name
.data(), Name
.size());
1473 SegLC
.cmd
= MachO::LC_SEGMENT_64
;
1474 SegLC
.cmdsize
= sizeof(MachO::segment_command_64
) +
1475 Secs
.size() * sizeof(MachO::section_64
);
1476 SegLC
.nsects
= Secs
.size();
1477 WriteMachOStruct(SegLC
);
1478 for (auto &SD
: Secs
) {
1480 SD
.AddFixups(P
- SecContent
.data());
1481 WriteMachOStruct(SD
.Sec
);
1485 WriteMachOStruct(Hdr
);
1486 if (!TextSections
.empty())
1487 WriteSegment("__TEXT", TextSections
);
1488 if (!DataSections
.empty())
1489 WriteSegment("__DATA", DataSections
);
1491 assert(P
== SecContent
.end() && "Underflow writing ObjC runtime object");
1492 return Error::success();
1495 } // End namespace orc.
1496 } // End namespace llvm.