xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
10 
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"
18 #include <optional>
19 
20 #define DEBUG_TYPE "orc"
21 
22 using namespace llvm;
23 using namespace llvm::orc;
24 using namespace llvm::orc::shared;
25 
26 namespace llvm {
27 namespace orc {
28 namespace shared {
29 
30 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
31 using SPSMachOJITDylibDepInfoMap =
32     SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
33 
34 template <>
35 class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
36                              MachOPlatform::MachOJITDylibDepInfo> {
37 public:
38   static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
39     return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
40   }
41 
42   static bool serialize(SPSOutputBuffer &OB,
43                         const MachOPlatform::MachOJITDylibDepInfo &DDI) {
44     return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
45                                                          DDI.DepHeaders);
46   }
47 
48   static bool deserialize(SPSInputBuffer &IB,
49                           MachOPlatform::MachOJITDylibDepInfo &DDI) {
50     return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
51                                                            DDI.DepHeaders);
52   }
53 };
54 
55 } // namespace shared
56 } // namespace orc
57 } // namespace llvm
58 
59 namespace {
60 
61 std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
62                                                         std::string Name) {
63   unsigned PointerSize;
64   support::endianness Endianness;
65   const auto &TT =
66       MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
67 
68   switch (TT.getArch()) {
69   case Triple::aarch64:
70   case Triple::x86_64:
71     PointerSize = 8;
72     Endianness = support::endianness::little;
73     break;
74   default:
75     llvm_unreachable("Unrecognized architecture");
76   }
77 
78   return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize,
79                                               Endianness,
80                                               jitlink::getGenericEdgeKindName);
81 }
82 
83 // Generates a MachO header.
84 class MachOHeaderMaterializationUnit : public MaterializationUnit {
85 public:
86   MachOHeaderMaterializationUnit(MachOPlatform &MOP,
87                                  const SymbolStringPtr &HeaderStartSymbol)
88       : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
89         MOP(MOP) {}
90 
91   StringRef getName() const override { return "MachOHeaderMU"; }
92 
93   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
94     auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
95     addMachOHeader(*G, MOP, R->getInitializerSymbol());
96     MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
97   }
98 
99   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
100 
101   static void addMachOHeader(jitlink::LinkGraph &G, MachOPlatform &MOP,
102                              const SymbolStringPtr &InitializerSymbol) {
103     auto &HeaderSection = G.createSection("__header", MemProt::Read);
104     auto &HeaderBlock = createHeaderBlock(G, HeaderSection);
105 
106     // Init symbol is header-start symbol.
107     G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol,
108                        HeaderBlock.getSize(), jitlink::Linkage::Strong,
109                        jitlink::Scope::Default, false, true);
110     for (auto &HS : AdditionalHeaderSymbols)
111       G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
112                          jitlink::Linkage::Strong, jitlink::Scope::Default,
113                          false, true);
114   }
115 
116 private:
117   struct HeaderSymbol {
118     const char *Name;
119     uint64_t Offset;
120   };
121 
122   static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
123       {"___mh_executable_header", 0}};
124 
125   static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
126                                            jitlink::Section &HeaderSection) {
127     MachO::mach_header_64 Hdr;
128     Hdr.magic = MachO::MH_MAGIC_64;
129     switch (G.getTargetTriple().getArch()) {
130     case Triple::aarch64:
131       Hdr.cputype = MachO::CPU_TYPE_ARM64;
132       Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
133       break;
134     case Triple::x86_64:
135       Hdr.cputype = MachO::CPU_TYPE_X86_64;
136       Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
137       break;
138     default:
139       llvm_unreachable("Unrecognized architecture");
140     }
141     Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
142     Hdr.ncmds = 0;
143     Hdr.sizeofcmds = 0;
144     Hdr.flags = 0;
145     Hdr.reserved = 0;
146 
147     if (G.getEndianness() != support::endian::system_endianness())
148       MachO::swapStruct(Hdr);
149 
150     auto HeaderContent = G.allocateString(
151         StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
152 
153     return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
154                                 0);
155   }
156 
157   static MaterializationUnit::Interface
158   createHeaderInterface(MachOPlatform &MOP,
159                         const SymbolStringPtr &HeaderStartSymbol) {
160     SymbolFlagsMap HeaderSymbolFlags;
161 
162     HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
163     for (auto &HS : AdditionalHeaderSymbols)
164       HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
165           JITSymbolFlags::Exported;
166 
167     return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
168                                           HeaderStartSymbol);
169   }
170 
171   MachOPlatform &MOP;
172 };
173 
174 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
175     MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
176 
177 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
178 class MachOPlatformCompleteBootstrapMaterializationUnit
179     : public MaterializationUnit {
180 public:
181   MachOPlatformCompleteBootstrapMaterializationUnit(
182       MachOPlatform &MOP, StringRef PlatformJDName,
183       SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs,
184       ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,
185       ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,
186       ExecutorAddr MachOHeaderAddr)
187       : MaterializationUnit(
188             {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
189         MOP(MOP), PlatformJDName(PlatformJDName),
190         CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
191         DeferredAAs(std::move(DeferredAAs)),
192         PlatformBootstrap(PlatformBootstrap),
193         PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
194         DeregisterJITDylib(DeregisterJITDylib),
195         MachOHeaderAddr(MachOHeaderAddr) {}
196 
197   StringRef getName() const override {
198     return "MachOPlatformCompleteBootstrap";
199   }
200 
201   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
202     using namespace jitlink;
203     auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");
204     auto &PlaceholderSection =
205         G->createSection("__orc_rt_cplt_bs", MemProt::Read);
206     auto &PlaceholderBlock =
207         G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);
208     G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,
209                         Linkage::Strong, Scope::Hidden, false, true);
210 
211     // Reserve space for the stolen actions, plus two extras.
212     G->allocActions().reserve(DeferredAAs.size() + 2);
213 
214     // 1. Bootstrap the platform support code.
215     G->allocActions().push_back(
216         {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),
217          cantFail(
218              WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
219 
220     // 2. Register the platform JITDylib.
221     G->allocActions().push_back(
222         {cantFail(WrapperFunctionCall::Create<
223                   SPSArgList<SPSString, SPSExecutorAddr>>(
224              RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),
225          cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
226              DeregisterJITDylib, MachOHeaderAddr))});
227 
228     // 3. Add the deferred actions to the graph.
229     std::move(DeferredAAs.begin(), DeferredAAs.end(),
230               std::back_inserter(G->allocActions()));
231 
232     MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
233   }
234 
235   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
236 
237 private:
238   MachOPlatform &MOP;
239   StringRef PlatformJDName;
240   SymbolStringPtr CompleteBootstrapSymbol;
241   shared::AllocActions DeferredAAs;
242   ExecutorAddr PlatformBootstrap;
243   ExecutorAddr PlatformShutdown;
244   ExecutorAddr RegisterJITDylib;
245   ExecutorAddr DeregisterJITDylib;
246   ExecutorAddr MachOHeaderAddr;
247 };
248 
249 StringRef DataCommonSectionName = "__DATA,__common";
250 StringRef DataDataSectionName = "__DATA,__data";
251 StringRef EHFrameSectionName = "__TEXT,__eh_frame";
252 StringRef CompactUnwindInfoSectionName = "__TEXT,__unwind_info";
253 StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
254 StringRef ObjCClassListSectionName = "__DATA,__objc_classlist";
255 StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info";
256 StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs";
257 StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto";
258 StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos";
259 StringRef Swift5TypesSectionName = "__TEXT,__swift5_types";
260 StringRef ThreadBSSSectionName = "__DATA,__thread_bss";
261 StringRef ThreadDataSectionName = "__DATA,__thread_data";
262 StringRef ThreadVarsSectionName = "__DATA,__thread_vars";
263 
264 StringRef InitSectionNames[] = {
265     ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName,
266     Swift5ProtosSectionName, Swift5ProtoSectionName, Swift5TypesSectionName};
267 
268 } // end anonymous namespace
269 
270 namespace llvm {
271 namespace orc {
272 
273 Expected<std::unique_ptr<MachOPlatform>>
274 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
275                       JITDylib &PlatformJD, const char *OrcRuntimePath,
276                       std::optional<SymbolAliasMap> RuntimeAliases) {
277 
278   auto &EPC = ES.getExecutorProcessControl();
279 
280   // If the target is not supported then bail out immediately.
281   if (!supportedTarget(EPC.getTargetTriple()))
282     return make_error<StringError>("Unsupported MachOPlatform triple: " +
283                                        EPC.getTargetTriple().str(),
284                                    inconvertibleErrorCode());
285 
286   // Create default aliases if the caller didn't supply any.
287   if (!RuntimeAliases)
288     RuntimeAliases = standardPlatformAliases(ES);
289 
290   // Define the aliases.
291   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
292     return std::move(Err);
293 
294   // Add JIT-dispatch function support symbols.
295   if (auto Err = PlatformJD.define(absoluteSymbols(
296           {{ES.intern("___orc_rt_jit_dispatch"),
297             {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
298              JITSymbolFlags::Exported}},
299            {ES.intern("___orc_rt_jit_dispatch_ctx"),
300             {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
301              JITSymbolFlags::Exported}}})))
302     return std::move(Err);
303 
304   // Create a generator for the ORC runtime archive.
305   auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
306       ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
307   if (!OrcRuntimeArchiveGenerator)
308     return OrcRuntimeArchiveGenerator.takeError();
309 
310   // Create the instance.
311   Error Err = Error::success();
312   auto P = std::unique_ptr<MachOPlatform>(
313       new MachOPlatform(ES, ObjLinkingLayer, PlatformJD,
314                         std::move(*OrcRuntimeArchiveGenerator), Err));
315   if (Err)
316     return std::move(Err);
317   return std::move(P);
318 }
319 
320 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
321   if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
322           *this, MachOHeaderStartSymbol)))
323     return Err;
324 
325   return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
326 }
327 
328 Error MachOPlatform::teardownJITDylib(JITDylib &JD) {
329   std::lock_guard<std::mutex> Lock(PlatformMutex);
330   auto I = JITDylibToHeaderAddr.find(&JD);
331   if (I != JITDylibToHeaderAddr.end()) {
332     assert(HeaderAddrToJITDylib.count(I->second) &&
333            "HeaderAddrToJITDylib missing entry");
334     HeaderAddrToJITDylib.erase(I->second);
335     JITDylibToHeaderAddr.erase(I);
336   }
337   JITDylibToPThreadKey.erase(&JD);
338   return Error::success();
339 }
340 
341 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
342                                   const MaterializationUnit &MU) {
343   auto &JD = RT.getJITDylib();
344   const auto &InitSym = MU.getInitializerSymbol();
345   if (!InitSym)
346     return Error::success();
347 
348   RegisteredInitSymbols[&JD].add(InitSym,
349                                  SymbolLookupFlags::WeaklyReferencedSymbol);
350   LLVM_DEBUG({
351     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
352            << MU.getName() << "\n";
353   });
354   return Error::success();
355 }
356 
357 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
358   llvm_unreachable("Not supported yet");
359 }
360 
361 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
362                        ArrayRef<std::pair<const char *, const char *>> AL) {
363   for (auto &KV : AL) {
364     auto AliasName = ES.intern(KV.first);
365     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
366     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
367                                      JITSymbolFlags::Exported};
368   }
369 }
370 
371 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
372   SymbolAliasMap Aliases;
373   addAliases(ES, Aliases, requiredCXXAliases());
374   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
375   return Aliases;
376 }
377 
378 ArrayRef<std::pair<const char *, const char *>>
379 MachOPlatform::requiredCXXAliases() {
380   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
381       {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
382 
383   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
384 }
385 
386 ArrayRef<std::pair<const char *, const char *>>
387 MachOPlatform::standardRuntimeUtilityAliases() {
388   static const std::pair<const char *, const char *>
389       StandardRuntimeUtilityAliases[] = {
390           {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
391           {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
392           {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
393           {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
394           {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
395           {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
396 
397   return ArrayRef<std::pair<const char *, const char *>>(
398       StandardRuntimeUtilityAliases);
399 }
400 
401 bool MachOPlatform::isInitializerSection(StringRef SegName,
402                                          StringRef SectName) {
403   for (auto &Name : InitSectionNames) {
404     if (Name.startswith(SegName) && Name.substr(7) == SectName)
405       return true;
406   }
407   return false;
408 }
409 
410 bool MachOPlatform::supportedTarget(const Triple &TT) {
411   switch (TT.getArch()) {
412   case Triple::aarch64:
413   case Triple::x86_64:
414     return true;
415   default:
416     return false;
417   }
418 }
419 
420 MachOPlatform::MachOPlatform(
421     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
422     JITDylib &PlatformJD,
423     std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
424     : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer) {
425   ErrorAsOutParameter _(&Err);
426   ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
427   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
428 
429   BootstrapInfo BI;
430   Bootstrap = &BI;
431 
432   // Bootstrap process -- here be phase-ordering dragons.
433   //
434   // The MachOPlatform class uses allocation actions to register metadata
435   // sections with the ORC runtime, however the runtime contains metadata
436   // registration functions that have their own metadata that they need to
437   // register (e.g. the frame-info registration functions have frame-info).
438   // We can't use an ordinary lookup to find these registration functions
439   // because their address is needed during the link of the containing graph
440   // itself (to build the allocation actions that will call the registration
441   // functions). Further complicating the situation (a) the graph containing
442   // the registration functions is allowed to depend on other graphs (e.g. the
443   // graph containing the ORC runtime RTTI support) so we need to handle with
444   // an unknown set of dependencies during bootstrap, and (b) these graphs may
445   // be linked concurrently if the user has installed a concurrent dispatcher.
446   //
447   // We satisfy these constraint by implementing a bootstrap phase during which
448   // allocation actions generated by MachOPlatform are appended to a list of
449   // deferred allocation actions, rather than to the graphs themselves. At the
450   // end of the bootstrap process the deferred actions are attached to a final
451   // "complete-bootstrap" graph that causes them to be run.
452   //
453   // The bootstrap steps are as follows:
454   //
455   // 1. Request the graph containing the mach header. This graph is guaranteed
456   //    not to have any metadata so the fact that the registration functions
457   //    are not available yet is not a problem.
458   //
459   // 2. Look up the registration functions and discard the results. This will
460   //    trigger linking of the graph containing these functions, and
461   //    consequently any graphs that it depends on. We do not use the lookup
462   //    result to find the addresses of the functions requested (as described
463   //    above the lookup will return too late for that), instead we capture the
464   //    addresses in a post-allocation pass injected by the platform runtime
465   //    during bootstrap only.
466   //
467   // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of
468   //    graphs being linked (potentially concurrently), and we block until all
469   //    of these graphs have completed linking. This is to avoid a race on the
470   //    deferred-actions vector: the lookup for the runtime registration
471   //    functions may return while some functions (those that are being
472   //    incidentally linked in, but aren't reachable via the runtime functions)
473   //    are still being linked, and we need to capture any allocation actions
474   //    for this incidental code before we proceed.
475   //
476   // 4. Once all active links are complete we transfer the deferred actions to
477   //    a newly added CompleteBootstrap graph and then request a symbol from
478   //    the CompleteBootstrap graph to trigger materialization. This will cause
479   //    all deferred actions to be run, and once this lookup returns we can
480   //    proceed.
481   //
482   // 5. Finally, we associate runtime support methods in MachOPlatform with
483   //    the corresponding jit-dispatch tag variables in the ORC runtime to make
484   //    the support methods callable. The bootstrap is now complete.
485 
486   // Step (1) Add header materialization unit and request.
487   if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>(
488            *this, MachOHeaderStartSymbol))))
489     return;
490   if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
491     return;
492 
493   // Step (2) Request runtime registration functions to trigger
494   // materialization..
495   if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
496                        SymbolLookupSet(
497                            {PlatformBootstrap.Name, PlatformShutdown.Name,
498                             RegisterJITDylib.Name, DeregisterJITDylib.Name,
499                             RegisterObjectPlatformSections.Name,
500                             DeregisterObjectPlatformSections.Name,
501                             CreatePThreadKey.Name}))
502                  .takeError()))
503     return;
504 
505   // Step (3) Wait for any incidental linker work to complete.
506   {
507     std::unique_lock<std::mutex> Lock(BI.Mutex);
508     BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
509     Bootstrap = nullptr;
510   }
511 
512   // Step (4) Add complete-bootstrap materialization unit and request.
513   auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap");
514   if ((Err = PlatformJD.define(
515            std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(
516                *this, PlatformJD.getName(), BootstrapCompleteSymbol,
517                std::move(BI.DeferredAAs), PlatformBootstrap.Addr,
518                PlatformShutdown.Addr, RegisterJITDylib.Addr,
519                DeregisterJITDylib.Addr, BI.MachOHeaderAddr))))
520     return;
521   if ((Err = ES.lookup(makeJITDylibSearchOrder(
522                            &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
523                        std::move(BootstrapCompleteSymbol))
524                  .takeError()))
525     return;
526 
527   // (5) Associate runtime support functions.
528   if ((Err = associateRuntimeSupportFunctions()))
529     return;
530 }
531 
532 Error MachOPlatform::associateRuntimeSupportFunctions() {
533   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
534 
535   using PushInitializersSPSSig =
536       SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);
537   WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
538       ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
539           this, &MachOPlatform::rt_pushInitializers);
540 
541   using LookupSymbolSPSSig =
542       SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
543   WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
544       ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
545                                               &MachOPlatform::rt_lookupSymbol);
546 
547   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
548 }
549 
550 void MachOPlatform::pushInitializersLoop(
551     PushInitializersSendResultFn SendResult, JITDylibSP JD) {
552   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
553   DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
554   SmallVector<JITDylib *, 16> Worklist({JD.get()});
555 
556   ES.runSessionLocked([&]() {
557     while (!Worklist.empty()) {
558       // FIXME: Check for defunct dylibs.
559 
560       auto DepJD = Worklist.back();
561       Worklist.pop_back();
562 
563       // If we've already visited this JITDylib on this iteration then continue.
564       if (JDDepMap.count(DepJD))
565         continue;
566 
567       // Add dep info.
568       auto &DM = JDDepMap[DepJD];
569       DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
570         for (auto &KV : O) {
571           if (KV.first == DepJD)
572             continue;
573           DM.push_back(KV.first);
574           Worklist.push_back(KV.first);
575         }
576       });
577 
578       // Add any registered init symbols.
579       auto RISItr = RegisteredInitSymbols.find(DepJD);
580       if (RISItr != RegisteredInitSymbols.end()) {
581         NewInitSymbols[DepJD] = std::move(RISItr->second);
582         RegisteredInitSymbols.erase(RISItr);
583       }
584     }
585   });
586 
587   // If there are no further init symbols to look up then send the link order
588   // (as a list of header addresses) to the caller.
589   if (NewInitSymbols.empty()) {
590 
591     // To make the list intelligible to the runtime we need to convert all
592     // JITDylib pointers to their header addresses. Only include JITDylibs
593     // that appear in the JITDylibToHeaderAddr map (i.e. those that have been
594     // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
595     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
596     HeaderAddrs.reserve(JDDepMap.size());
597     {
598       std::lock_guard<std::mutex> Lock(PlatformMutex);
599       for (auto &KV : JDDepMap) {
600         auto I = JITDylibToHeaderAddr.find(KV.first);
601         if (I != JITDylibToHeaderAddr.end())
602           HeaderAddrs[KV.first] = I->second;
603       }
604     }
605 
606     // Build the dep info map to return.
607     MachOJITDylibDepInfoMap DIM;
608     DIM.reserve(JDDepMap.size());
609     for (auto &KV : JDDepMap) {
610       auto HI = HeaderAddrs.find(KV.first);
611       // Skip unmanaged JITDylibs.
612       if (HI == HeaderAddrs.end())
613         continue;
614       auto H = HI->second;
615       MachOJITDylibDepInfo DepInfo;
616       for (auto &Dep : KV.second) {
617         auto HJ = HeaderAddrs.find(Dep);
618         if (HJ != HeaderAddrs.end())
619           DepInfo.DepHeaders.push_back(HJ->second);
620       }
621       DIM.push_back(std::make_pair(H, std::move(DepInfo)));
622     }
623     SendResult(DIM);
624     return;
625   }
626 
627   // Otherwise issue a lookup and re-run this phase when it completes.
628   lookupInitSymbolsAsync(
629       [this, SendResult = std::move(SendResult), JD](Error Err) mutable {
630         if (Err)
631           SendResult(std::move(Err));
632         else
633           pushInitializersLoop(std::move(SendResult), JD);
634       },
635       ES, std::move(NewInitSymbols));
636 }
637 
638 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
639                                         ExecutorAddr JDHeaderAddr) {
640   JITDylibSP JD;
641   {
642     std::lock_guard<std::mutex> Lock(PlatformMutex);
643     auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
644     if (I != HeaderAddrToJITDylib.end())
645       JD = I->second;
646   }
647 
648   LLVM_DEBUG({
649     dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
650     if (JD)
651       dbgs() << "pushing initializers for " << JD->getName() << "\n";
652     else
653       dbgs() << "No JITDylib for header address.\n";
654   });
655 
656   if (!JD) {
657     SendResult(
658         make_error<StringError>("No JITDylib with header addr " +
659                                     formatv("{0:x}", JDHeaderAddr.getValue()),
660                                 inconvertibleErrorCode()));
661     return;
662   }
663 
664   pushInitializersLoop(std::move(SendResult), JD);
665 }
666 
667 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
668                                     ExecutorAddr Handle, StringRef SymbolName) {
669   LLVM_DEBUG({
670     dbgs() << "MachOPlatform::rt_lookupSymbol(\""
671            << formatv("{0:x}", Handle.getValue()) << "\")\n";
672   });
673 
674   JITDylib *JD = nullptr;
675 
676   {
677     std::lock_guard<std::mutex> Lock(PlatformMutex);
678     auto I = HeaderAddrToJITDylib.find(Handle);
679     if (I != HeaderAddrToJITDylib.end())
680       JD = I->second;
681   }
682 
683   if (!JD) {
684     LLVM_DEBUG({
685       dbgs() << "  No JITDylib for handle "
686              << formatv("{0:x}", Handle.getValue()) << "\n";
687     });
688     SendResult(make_error<StringError>("No JITDylib associated with handle " +
689                                            formatv("{0:x}", Handle.getValue()),
690                                        inconvertibleErrorCode()));
691     return;
692   }
693 
694   // Use functor class to work around XL build compiler issue on AIX.
695   class RtLookupNotifyComplete {
696   public:
697     RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
698         : SendResult(std::move(SendResult)) {}
699     void operator()(Expected<SymbolMap> Result) {
700       if (Result) {
701         assert(Result->size() == 1 && "Unexpected result map count");
702         SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
703       } else {
704         SendResult(Result.takeError());
705       }
706     }
707 
708   private:
709     SendSymbolAddressFn SendResult;
710   };
711 
712   // FIXME: Proper mangling.
713   auto MangledName = ("_" + SymbolName).str();
714   ES.lookup(
715       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
716       SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
717       RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
718 }
719 
720 Expected<uint64_t> MachOPlatform::createPThreadKey() {
721   if (!CreatePThreadKey.Addr)
722     return make_error<StringError>(
723         "Attempting to create pthread key in target, but runtime support has "
724         "not been loaded yet",
725         inconvertibleErrorCode());
726 
727   Expected<uint64_t> Result(0);
728   if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
729           CreatePThreadKey.Addr, Result))
730     return std::move(Err);
731   return Result;
732 }
733 
734 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
735     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
736     jitlink::PassConfiguration &Config) {
737 
738   using namespace jitlink;
739 
740   bool InBootstrapPhase =
741       &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
742 
743   // If we're in the bootstrap phase then increment the active graphs.
744   if (InBootstrapPhase) {
745     Config.PrePrunePasses.push_back(
746         [this](LinkGraph &G) { return bootstrapPipelineStart(G); });
747     Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
748       return bootstrapPipelineRecordRuntimeFunctions(G);
749     });
750   }
751 
752   // --- Handle Initializers ---
753   if (auto InitSymbol = MR.getInitializerSymbol()) {
754 
755     // If the initializer symbol is the MachOHeader start symbol then just
756     // register it and then bail out -- the header materialization unit
757     // definitely doesn't need any other passes.
758     if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) {
759       Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
760         return associateJITDylibHeaderSymbol(G, MR);
761       });
762       return;
763     }
764 
765     // If the object contains an init symbol other than the header start symbol
766     // then add passes to preserve, process and register the init
767     // sections/symbols.
768     Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
769       if (auto Err = preserveInitSections(G, MR))
770         return Err;
771       return processObjCImageInfo(G, MR);
772     });
773   }
774 
775   // Insert TLV lowering at the start of the PostPrunePasses, since we want
776   // it to run before GOT/PLT lowering.
777   Config.PostPrunePasses.insert(
778       Config.PostPrunePasses.begin(),
779       [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) {
780         return fixTLVSectionsAndEdges(G, JD);
781       });
782 
783   // Add a pass to register the final addresses of any special sections in the
784   // object with the runtime.
785   Config.PostAllocationPasses.push_back(
786       [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) {
787         return registerObjectPlatformSections(G, JD, InBootstrapPhase);
788       });
789 
790   // If we're in the bootstrap phase then steal allocation actions and then
791   // decrement the active graphs.
792   if (InBootstrapPhase)
793     Config.PostFixupPasses.push_back(
794         [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });
795 }
796 
797 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
798 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
799     MaterializationResponsibility &MR) {
800   std::lock_guard<std::mutex> Lock(PluginMutex);
801   auto I = InitSymbolDeps.find(&MR);
802   if (I != InitSymbolDeps.end()) {
803     SyntheticSymbolDependenciesMap Result;
804     Result[MR.getInitializerSymbol()] = std::move(I->second);
805     InitSymbolDeps.erase(&MR);
806     return Result;
807   }
808   return SyntheticSymbolDependenciesMap();
809 }
810 
811 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart(
812     jitlink::LinkGraph &G) {
813   // Increment the active graphs count in BootstrapInfo.
814   std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
815   ++MP.Bootstrap.load()->ActiveGraphs;
816   return Error::success();
817 }
818 
819 Error MachOPlatform::MachOPlatformPlugin::
820     bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {
821   // Record bootstrap function names.
822   std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {
823       {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr},
824       {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},
825       {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},
826       {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},
827       {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},
828       {*MP.RegisterObjectPlatformSections.Name,
829        &MP.RegisterObjectPlatformSections.Addr},
830       {*MP.DeregisterObjectPlatformSections.Name,
831        &MP.DeregisterObjectPlatformSections.Addr},
832       {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}};
833 
834   bool RegisterMachOHeader = false;
835 
836   for (auto *Sym : G.defined_symbols()) {
837     for (auto &RTSym : RuntimeSymbols) {
838       if (Sym->hasName() && Sym->getName() == RTSym.first) {
839         if (*RTSym.second)
840           return make_error<StringError>(
841               "Duplicate " + RTSym.first +
842                   " detected during MachOPlatform bootstrap",
843               inconvertibleErrorCode());
844 
845         if (Sym->getName() == *MP.MachOHeaderStartSymbol)
846           RegisterMachOHeader = true;
847 
848         *RTSym.second = Sym->getAddress();
849       }
850     }
851   }
852 
853   if (RegisterMachOHeader) {
854     // If this graph defines the macho header symbol then create the internal
855     // mapping between it and PlatformJD.
856     std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
857     MP.JITDylibToHeaderAddr[&MP.PlatformJD] =
858         MP.Bootstrap.load()->MachOHeaderAddr;
859     MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] =
860         &MP.PlatformJD;
861   }
862 
863   return Error::success();
864 }
865 
866 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
867     jitlink::LinkGraph &G) {
868   std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex);
869   assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed");
870   --MP.Bootstrap.load()->ActiveGraphs;
871   // Notify Bootstrap->CV while holding the mutex because the mutex is
872   // also keeping Bootstrap->CV alive.
873   if (MP.Bootstrap.load()->ActiveGraphs == 0)
874     MP.Bootstrap.load()->CV.notify_all();
875   return Error::success();
876 }
877 
878 Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
879     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
880   auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
881     return Sym->getName() == *MP.MachOHeaderStartSymbol;
882   });
883   assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
884 
885   auto &JD = MR.getTargetJITDylib();
886   std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
887   auto HeaderAddr = (*I)->getAddress();
888   MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
889   MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
890   // We can unconditionally add these actions to the Graph because this pass
891   // isn't used during bootstrap.
892   G.allocActions().push_back(
893       {cantFail(
894            WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(
895                MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),
896        cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
897            MP.DeregisterJITDylib.Addr, HeaderAddr))});
898   return Error::success();
899 }
900 
901 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
902     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
903 
904   JITLinkSymbolSet InitSectionSymbols;
905   for (auto &InitSectionName : InitSectionNames) {
906     // Skip non-init sections.
907     auto *InitSection = G.findSectionByName(InitSectionName);
908     if (!InitSection)
909       continue;
910 
911     // Make a pass over live symbols in the section: those blocks are already
912     // preserved.
913     DenseSet<jitlink::Block *> AlreadyLiveBlocks;
914     for (auto &Sym : InitSection->symbols()) {
915       auto &B = Sym->getBlock();
916       if (Sym->isLive() && Sym->getOffset() == 0 &&
917           Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
918         InitSectionSymbols.insert(Sym);
919         AlreadyLiveBlocks.insert(&B);
920       }
921     }
922 
923     // Add anonymous symbols to preserve any not-already-preserved blocks.
924     for (auto *B : InitSection->blocks())
925       if (!AlreadyLiveBlocks.count(B))
926         InitSectionSymbols.insert(
927             &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
928   }
929 
930   if (!InitSectionSymbols.empty()) {
931     std::lock_guard<std::mutex> Lock(PluginMutex);
932     InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
933   }
934 
935   return Error::success();
936 }
937 
938 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
939     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
940 
941   // If there's an ObjC imagine info then either
942   //   (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
943   //       this case we name and record it.
944   // OR
945   //   (2) We already have a recorded __objc_imageinfo for this JITDylib,
946   //       in which case we just verify it.
947   auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName);
948   if (!ObjCImageInfo)
949     return Error::success();
950 
951   auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
952 
953   // Check that the section is not empty if present.
954   if (ObjCImageInfoBlocks.empty())
955     return make_error<StringError>("Empty " + ObjCImageInfoSectionName +
956                                        " section in " + G.getName(),
957                                    inconvertibleErrorCode());
958 
959   // Check that there's only one block in the section.
960   if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
961     return make_error<StringError>("Multiple blocks in " +
962                                        ObjCImageInfoSectionName +
963                                        " section in " + G.getName(),
964                                    inconvertibleErrorCode());
965 
966   // Check that the __objc_imageinfo section is unreferenced.
967   // FIXME: We could optimize this check if Symbols had a ref-count.
968   for (auto &Sec : G.sections()) {
969     if (&Sec != ObjCImageInfo)
970       for (auto *B : Sec.blocks())
971         for (auto &E : B->edges())
972           if (E.getTarget().isDefined() &&
973               &E.getTarget().getBlock().getSection() == ObjCImageInfo)
974             return make_error<StringError>(ObjCImageInfoSectionName +
975                                                " is referenced within file " +
976                                                G.getName(),
977                                            inconvertibleErrorCode());
978   }
979 
980   auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
981   auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
982   auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
983   auto Flags =
984       support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
985 
986   // Lock the mutex while we verify / update the ObjCImageInfos map.
987   std::lock_guard<std::mutex> Lock(PluginMutex);
988 
989   auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
990   if (ObjCImageInfoItr != ObjCImageInfos.end()) {
991     // We've already registered an __objc_imageinfo section. Verify the
992     // content of this new section matches, then delete it.
993     if (ObjCImageInfoItr->second.first != Version)
994       return make_error<StringError>(
995           "ObjC version in " + G.getName() +
996               " does not match first registered version",
997           inconvertibleErrorCode());
998     if (ObjCImageInfoItr->second.second != Flags)
999       return make_error<StringError>("ObjC flags in " + G.getName() +
1000                                          " do not match first registered flags",
1001                                      inconvertibleErrorCode());
1002 
1003     // __objc_imageinfo is valid. Delete the block.
1004     for (auto *S : ObjCImageInfo->symbols())
1005       G.removeDefinedSymbol(*S);
1006     G.removeBlock(ObjCImageInfoBlock);
1007   } else {
1008     // We haven't registered an __objc_imageinfo section yet. Register and
1009     // move on. The section should already be marked no-dead-strip.
1010     ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
1011   }
1012 
1013   return Error::success();
1014 }
1015 
1016 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1017     jitlink::LinkGraph &G, JITDylib &JD) {
1018 
1019   // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
1020   for (auto *Sym : G.external_symbols())
1021     if (Sym->getName() == "__tlv_bootstrap") {
1022       Sym->setName("___orc_rt_macho_tlv_get_addr");
1023       break;
1024     }
1025 
1026   // Store key in __thread_vars struct fields.
1027   if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) {
1028     std::optional<uint64_t> Key;
1029     {
1030       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1031       auto I = MP.JITDylibToPThreadKey.find(&JD);
1032       if (I != MP.JITDylibToPThreadKey.end())
1033         Key = I->second;
1034     }
1035 
1036     if (!Key) {
1037       if (auto KeyOrErr = MP.createPThreadKey())
1038         Key = *KeyOrErr;
1039       else
1040         return KeyOrErr.takeError();
1041     }
1042 
1043     uint64_t PlatformKeyBits =
1044         support::endian::byte_swap(*Key, G.getEndianness());
1045 
1046     for (auto *B : ThreadDataSec->blocks()) {
1047       if (B->getSize() != 3 * G.getPointerSize())
1048         return make_error<StringError>("__thread_vars block at " +
1049                                            formatv("{0:x}", B->getAddress()) +
1050                                            " has unexpected size",
1051                                        inconvertibleErrorCode());
1052 
1053       auto NewBlockContent = G.allocateBuffer(B->getSize());
1054       llvm::copy(B->getContent(), NewBlockContent.data());
1055       memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
1056              G.getPointerSize());
1057       B->setContent(NewBlockContent);
1058     }
1059   }
1060 
1061   // Transform any TLV edges into GOT edges.
1062   for (auto *B : G.blocks())
1063     for (auto &E : B->edges())
1064       if (E.getKind() ==
1065           jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
1066         E.setKind(jitlink::x86_64::
1067                       RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1068 
1069   return Error::success();
1070 }
1071 
1072 std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
1073 MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1074     jitlink::LinkGraph &G) {
1075   using namespace jitlink;
1076 
1077   UnwindSections US;
1078 
1079   // ScanSection records a section range and adds any executable blocks that
1080   // that section points to to the CodeBlocks vector.
1081   SmallVector<Block *> CodeBlocks;
1082   auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) {
1083     if (Sec.blocks().empty())
1084       return;
1085     SecRange = (*Sec.blocks().begin())->getRange();
1086     for (auto *B : Sec.blocks()) {
1087       auto R = B->getRange();
1088       SecRange.Start = std::min(SecRange.Start, R.Start);
1089       SecRange.End = std::max(SecRange.End, R.End);
1090       for (auto &E : B->edges()) {
1091         if (!E.getTarget().isDefined())
1092           continue;
1093         auto &TargetBlock = E.getTarget().getBlock();
1094         auto &TargetSection = TargetBlock.getSection();
1095         if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec)
1096           CodeBlocks.push_back(&TargetBlock);
1097       }
1098     }
1099   };
1100 
1101   if (Section *EHFrameSec = G.findSectionByName(EHFrameSectionName))
1102     ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection);
1103 
1104   if (Section *CUInfoSec = G.findSectionByName(CompactUnwindInfoSectionName))
1105     ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection);
1106 
1107   // If we didn't find any pointed-to code-blocks then there's no need to
1108   // register any info.
1109   if (CodeBlocks.empty())
1110     return std::nullopt;
1111 
1112   // We have info to register. Sort the code blocks into address order and
1113   // build a list of contiguous address ranges covering them all.
1114   llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) {
1115     return LHS->getAddress() < RHS->getAddress();
1116   });
1117   for (auto *B : CodeBlocks) {
1118     if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())
1119       US.CodeRanges.push_back(B->getRange());
1120     else
1121       US.CodeRanges.back().End = B->getRange().End;
1122   }
1123 
1124   LLVM_DEBUG({
1125     dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"
1126            << "  DWARF: ";
1127     if (US.DwarfSection.Start)
1128       dbgs() << US.DwarfSection << "\n";
1129     else
1130       dbgs() << "none\n";
1131     dbgs() << "  Compact-unwind: ";
1132     if (US.CompactUnwindSection.Start)
1133       dbgs() << US.CompactUnwindSection << "\n";
1134     else
1135       dbgs() << "none\n"
1136              << "for code ranges:\n";
1137     for (auto &CR : US.CodeRanges)
1138       dbgs() << "  " << CR << "\n";
1139     if (US.CodeRanges.size() >= G.sections_size())
1140       dbgs() << "WARNING: High number of discontiguous code ranges! "
1141                 "Padding may be interfering with coalescing.\n";
1142   });
1143 
1144   return US;
1145 }
1146 
1147 Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1148     jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) {
1149 
1150   // Get a pointer to the thread data section if there is one. It will be used
1151   // below.
1152   jitlink::Section *ThreadDataSection =
1153       G.findSectionByName(ThreadDataSectionName);
1154 
1155   // Handle thread BSS section if there is one.
1156   if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) {
1157     // If there's already a thread data section in this graph then merge the
1158     // thread BSS section content into it, otherwise just treat the thread
1159     // BSS section as the thread data section.
1160     if (ThreadDataSection)
1161       G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
1162     else
1163       ThreadDataSection = ThreadBSSSection;
1164   }
1165 
1166   SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
1167 
1168   // Collect data sections to register.
1169   StringRef DataSections[] = {DataDataSectionName, DataCommonSectionName,
1170                               EHFrameSectionName};
1171   for (auto &SecName : DataSections) {
1172     if (auto *Sec = G.findSectionByName(SecName)) {
1173       jitlink::SectionRange R(*Sec);
1174       if (!R.empty())
1175         MachOPlatformSecs.push_back({SecName, R.getRange()});
1176     }
1177   }
1178 
1179   // Having merged thread BSS (if present) and thread data (if present),
1180   // record the resulting section range.
1181   if (ThreadDataSection) {
1182     jitlink::SectionRange R(*ThreadDataSection);
1183     if (!R.empty())
1184       MachOPlatformSecs.push_back({ThreadDataSectionName, R.getRange()});
1185   }
1186 
1187   // If any platform sections were found then add an allocation action to call
1188   // the registration function.
1189   StringRef PlatformSections[] = {
1190       ModInitFuncSectionName,   ObjCClassListSectionName,
1191       ObjCImageInfoSectionName, ObjCSelRefsSectionName,
1192       Swift5ProtoSectionName,   Swift5ProtosSectionName,
1193       Swift5TypesSectionName,
1194   };
1195 
1196   for (auto &SecName : PlatformSections) {
1197     auto *Sec = G.findSectionByName(SecName);
1198     if (!Sec)
1199       continue;
1200     jitlink::SectionRange R(*Sec);
1201     if (R.empty())
1202       continue;
1203 
1204     MachOPlatformSecs.push_back({SecName, R.getRange()});
1205   }
1206 
1207   std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1208                            ExecutorAddrRange>>
1209       UnwindInfo;
1210   if (auto UI = findUnwindSectionInfo(G))
1211     UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1212                                  UI->CompactUnwindSection);
1213 
1214   if (!MachOPlatformSecs.empty() || UnwindInfo) {
1215     ExecutorAddr HeaderAddr;
1216     {
1217       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1218       auto I = MP.JITDylibToHeaderAddr.find(&JD);
1219       assert(I != MP.JITDylibToHeaderAddr.end() &&
1220              "Missing header for JITDylib");
1221       HeaderAddr = I->second;
1222     }
1223 
1224     // Dump the scraped inits.
1225     LLVM_DEBUG({
1226       dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
1227       for (auto &KV : MachOPlatformSecs)
1228         dbgs() << "  " << KV.first << ": " << KV.second << "\n";
1229     });
1230 
1231     using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1232         SPSExecutorAddr,
1233         SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,
1234                              SPSExecutorAddrRange, SPSExecutorAddrRange>>,
1235         SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
1236 
1237     shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
1238                                              ? G.allocActions()
1239                                              : MP.Bootstrap.load()->DeferredAAs;
1240 
1241     allocActions.push_back(
1242         {cantFail(
1243              WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1244                  MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,
1245                  MachOPlatformSecs)),
1246          cantFail(
1247              WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1248                  MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,
1249                  UnwindInfo, MachOPlatformSecs))});
1250   }
1251 
1252   return Error::success();
1253 }
1254 
1255 } // End namespace orc.
1256 } // End namespace llvm.
1257