xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp (revision f126890ac5386406dadf7c4cfa9566cbb56537c5)
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/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"
21 #include <optional>
22 
23 #define DEBUG_TYPE "orc"
24 
25 using namespace llvm;
26 using namespace llvm::orc;
27 using namespace llvm::orc::shared;
28 
29 namespace llvm {
30 namespace orc {
31 namespace shared {
32 
33 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
34 using SPSMachOJITDylibDepInfoMap =
35     SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
36 
37 template <>
38 class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
39                              MachOPlatform::MachOJITDylibDepInfo> {
40 public:
41   static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
42     return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
43   }
44 
45   static bool serialize(SPSOutputBuffer &OB,
46                         const MachOPlatform::MachOJITDylibDepInfo &DDI) {
47     return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
48                                                          DDI.DepHeaders);
49   }
50 
51   static bool deserialize(SPSInputBuffer &IB,
52                           MachOPlatform::MachOJITDylibDepInfo &DDI) {
53     return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
54                                                            DDI.DepHeaders);
55   }
56 };
57 
58 } // namespace shared
59 } // namespace orc
60 } // namespace llvm
61 
62 namespace {
63 
64 std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
65                                                         std::string Name) {
66   unsigned PointerSize;
67   support::endianness Endianness;
68   const auto &TT = MOP.getExecutionSession().getTargetTriple();
69 
70   switch (TT.getArch()) {
71   case Triple::aarch64:
72   case Triple::x86_64:
73     PointerSize = 8;
74     Endianness = support::endianness::little;
75     break;
76   default:
77     llvm_unreachable("Unrecognized architecture");
78   }
79 
80   return std::make_unique<jitlink::LinkGraph>(std::move(Name), TT, PointerSize,
81                                               Endianness,
82                                               jitlink::getGenericEdgeKindName);
83 }
84 
85 // Generates a MachO header.
86 class MachOHeaderMaterializationUnit : public MaterializationUnit {
87 public:
88   MachOHeaderMaterializationUnit(MachOPlatform &MOP,
89                                  const SymbolStringPtr &HeaderStartSymbol)
90       : MaterializationUnit(createHeaderInterface(MOP, HeaderStartSymbol)),
91         MOP(MOP) {}
92 
93   StringRef getName() const override { return "MachOHeaderMU"; }
94 
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));
99   }
100 
101   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
102 
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);
107 
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,
115                          false, true);
116   }
117 
118 private:
119   struct HeaderSymbol {
120     const char *Name;
121     uint64_t Offset;
122   };
123 
124   static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
125       {"___mh_executable_header", 0}};
126 
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;
135       break;
136     case Triple::x86_64:
137       Hdr.cputype = MachO::CPU_TYPE_X86_64;
138       Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
139       break;
140     default:
141       llvm_unreachable("Unrecognized architecture");
142     }
143     Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
144     Hdr.ncmds = 0;
145     Hdr.sizeofcmds = 0;
146     Hdr.flags = 0;
147     Hdr.reserved = 0;
148 
149     if (G.getEndianness() != support::endian::system_endianness())
150       MachO::swapStruct(Hdr);
151 
152     auto HeaderContent = G.allocateContent(
153         ArrayRef<char>(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
154 
155     return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
156                                 0);
157   }
158 
159   static MaterializationUnit::Interface
160   createHeaderInterface(MachOPlatform &MOP,
161                         const SymbolStringPtr &HeaderStartSymbol) {
162     SymbolFlagsMap HeaderSymbolFlags;
163 
164     HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
165     for (auto &HS : AdditionalHeaderSymbols)
166       HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
167           JITSymbolFlags::Exported;
168 
169     return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
170                                           HeaderStartSymbol);
171   }
172 
173   MachOPlatform &MOP;
174 };
175 
176 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
177     MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
178 
179 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
180 class MachOPlatformCompleteBootstrapMaterializationUnit
181     : public MaterializationUnit {
182 public:
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) {}
198 
199   StringRef getName() const override {
200     return "MachOPlatformCompleteBootstrap";
201   }
202 
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);
212 
213     // Reserve space for the stolen actions, plus two extras.
214     G->allocActions().reserve(DeferredAAs.size() + 2);
215 
216     // 1. Bootstrap the platform support code.
217     G->allocActions().push_back(
218         {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),
219          cantFail(
220              WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
221 
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))});
229 
230     // 3. Add the deferred actions to the graph.
231     std::move(DeferredAAs.begin(), DeferredAAs.end(),
232               std::back_inserter(G->allocActions()));
233 
234     MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
235   }
236 
237   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
238 
239 private:
240   MachOPlatform &MOP;
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;
249 };
250 
251 static StringRef ObjCRuntimeObjectSectionsData[] = {
252     MachOObjCCatListSectionName,   MachOObjCClassListSectionName,
253     MachOObjCClassRefsSectionName, MachOObjCConstSectionName,
254     MachOObjCDataSectionName,      MachOObjCSelRefsSectionName};
255 
256 static StringRef ObjCRuntimeObjectSectionsText[] = {
257     MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,
258     MachOObjCMethTypeSectionName,  MachOSwift5TypesSectionName,
259     MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
260     MachOSwift5EntrySectionName,   MachOSwift5ProtoSectionName,
261     MachOSwift5ProtosSectionName};
262 
263 static StringRef ObjCRuntimeObjectSectionName =
264     "__llvm_jitlink_ObjCRuntimeRegistrationObject";
265 
266 static StringRef ObjCImageInfoSymbolName =
267     "__llvm_jitlink_macho_objc_imageinfo";
268 
269 } // end anonymous namespace
270 
271 namespace llvm {
272 namespace orc {
273 
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) {
279 
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());
285 
286   auto &EPC = ES.getExecutorProcessControl();
287 
288   // Create default aliases if the caller didn't supply any.
289   if (!RuntimeAliases)
290     RuntimeAliases = standardPlatformAliases(ES);
291 
292   // Define the aliases.
293   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
294     return std::move(Err);
295 
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);
305 
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));
310   if (Err)
311     return std::move(Err);
312   return std::move(P);
313 }
314 
315 Expected<std::unique_ptr<MachOPlatform>>
316 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
317                       JITDylib &PlatformJD, const char *OrcRuntimePath,
318                       std::optional<SymbolAliasMap> RuntimeAliases) {
319 
320   // Create a generator for the ORC runtime archive.
321   auto OrcRuntimeArchiveGenerator =
322       StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
323   if (!OrcRuntimeArchiveGenerator)
324     return OrcRuntimeArchiveGenerator.takeError();
325 
326   return Create(ES, ObjLinkingLayer, PlatformJD,
327                 std::move(*OrcRuntimeArchiveGenerator),
328                 std::move(RuntimeAliases));
329 }
330 
331 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
332   if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
333           *this, MachOHeaderStartSymbol)))
334     return Err;
335 
336   return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
337 }
338 
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);
347   }
348   JITDylibToPThreadKey.erase(&JD);
349   return Error::success();
350 }
351 
352 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
353                                   const MaterializationUnit &MU) {
354   auto &JD = RT.getJITDylib();
355   const auto &InitSym = MU.getInitializerSymbol();
356   if (!InitSym)
357     return Error::success();
358 
359   RegisteredInitSymbols[&JD].add(InitSym,
360                                  SymbolLookupFlags::WeaklyReferencedSymbol);
361   LLVM_DEBUG({
362     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
363            << MU.getName() << "\n";
364   });
365   return Error::success();
366 }
367 
368 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
369   llvm_unreachable("Not supported yet");
370 }
371 
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};
379   }
380 }
381 
382 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
383   SymbolAliasMap Aliases;
384   addAliases(ES, Aliases, requiredCXXAliases());
385   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
386   return Aliases;
387 }
388 
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"}};
393 
394   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
395 }
396 
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"}};
407 
408   return ArrayRef<std::pair<const char *, const char *>>(
409       StandardRuntimeUtilityAliases);
410 }
411 
412 bool MachOPlatform::supportedTarget(const Triple &TT) {
413   switch (TT.getArch()) {
414   case Triple::aarch64:
415   case Triple::x86_64:
416     return true;
417   default:
418     return false;
419   }
420 }
421 
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));
430 
431   BootstrapInfo BI;
432   Bootstrap = &BI;
433 
434   // Bootstrap process -- here be phase-ordering dragons.
435   //
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.
448   //
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.
454   //
455   // The bootstrap steps are as follows:
456   //
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.
460   //
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.
468   //
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.
477   //
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
482   //    proceed.
483   //
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.
487 
488   // Step (1) Add header materialization unit and request.
489   if ((Err = PlatformJD.define(std::make_unique<MachOHeaderMaterializationUnit>(
490            *this, MachOHeaderStartSymbol))))
491     return;
492   if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
493     return;
494 
495   // Step (2) Request runtime registration functions to trigger
496   // materialization..
497   if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
498                        SymbolLookupSet(
499                            {PlatformBootstrap.Name, PlatformShutdown.Name,
500                             RegisterJITDylib.Name, DeregisterJITDylib.Name,
501                             RegisterObjectPlatformSections.Name,
502                             DeregisterObjectPlatformSections.Name,
503                             CreatePThreadKey.Name}))
504                  .takeError()))
505     return;
506 
507   // Step (3) Wait for any incidental linker work to complete.
508   {
509     std::unique_lock<std::mutex> Lock(BI.Mutex);
510     BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
511     Bootstrap = nullptr;
512   }
513 
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))))
522     return;
523   if ((Err = ES.lookup(makeJITDylibSearchOrder(
524                            &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
525                        std::move(BootstrapCompleteSymbol))
526                  .takeError()))
527     return;
528 
529   // (5) Associate runtime support functions.
530   if ((Err = associateRuntimeSupportFunctions()))
531     return;
532 }
533 
534 Error MachOPlatform::associateRuntimeSupportFunctions() {
535   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
536 
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);
542 
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);
548 
549   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
550 }
551 
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()});
557 
558   ES.runSessionLocked([&]() {
559     while (!Worklist.empty()) {
560       // FIXME: Check for defunct dylibs.
561 
562       auto DepJD = Worklist.back();
563       Worklist.pop_back();
564 
565       // If we've already visited this JITDylib on this iteration then continue.
566       if (JDDepMap.count(DepJD))
567         continue;
568 
569       // Add dep info.
570       auto &DM = JDDepMap[DepJD];
571       DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
572         for (auto &KV : O) {
573           if (KV.first == DepJD)
574             continue;
575           DM.push_back(KV.first);
576           Worklist.push_back(KV.first);
577         }
578       });
579 
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);
585       }
586     }
587   });
588 
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()) {
592 
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());
599     {
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;
605       }
606     }
607 
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())
615         continue;
616       auto H = HI->second;
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);
622       }
623       DIM.push_back(std::make_pair(H, std::move(DepInfo)));
624     }
625     SendResult(DIM);
626     return;
627   }
628 
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 {
632         if (Err)
633           SendResult(std::move(Err));
634         else
635           pushInitializersLoop(std::move(SendResult), JD);
636       },
637       ES, std::move(NewInitSymbols));
638 }
639 
640 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
641                                         ExecutorAddr JDHeaderAddr) {
642   JITDylibSP JD;
643   {
644     std::lock_guard<std::mutex> Lock(PlatformMutex);
645     auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
646     if (I != HeaderAddrToJITDylib.end())
647       JD = I->second;
648   }
649 
650   LLVM_DEBUG({
651     dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
652     if (JD)
653       dbgs() << "pushing initializers for " << JD->getName() << "\n";
654     else
655       dbgs() << "No JITDylib for header address.\n";
656   });
657 
658   if (!JD) {
659     SendResult(make_error<StringError>("No JITDylib with header addr " +
660                                            formatv("{0:x}", JDHeaderAddr),
661                                        inconvertibleErrorCode()));
662     return;
663   }
664 
665   pushInitializersLoop(std::move(SendResult), JD);
666 }
667 
668 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
669                                     ExecutorAddr Handle, StringRef SymbolName) {
670   LLVM_DEBUG({
671     dbgs() << "MachOPlatform::rt_lookupSymbol(\"" << Handle << "\")\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(dbgs() << "  No JITDylib for handle " << Handle << "\n");
685     SendResult(make_error<StringError>("No JITDylib associated with handle " +
686                                            formatv("{0:x}", Handle),
687                                        inconvertibleErrorCode()));
688     return;
689   }
690 
691   // Use functor class to work around XL build compiler issue on AIX.
692   class RtLookupNotifyComplete {
693   public:
694     RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
695         : SendResult(std::move(SendResult)) {}
696     void operator()(Expected<SymbolMap> Result) {
697       if (Result) {
698         assert(Result->size() == 1 && "Unexpected result map count");
699         SendResult(Result->begin()->second.getAddress());
700       } else {
701         SendResult(Result.takeError());
702       }
703     }
704 
705   private:
706     SendSymbolAddressFn SendResult;
707   };
708 
709   // FIXME: Proper mangling.
710   auto MangledName = ("_" + SymbolName).str();
711   ES.lookup(
712       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
713       SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
714       RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
715 }
716 
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());
723 
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);
728   return Result;
729 }
730 
731 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
732     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
733     jitlink::PassConfiguration &Config) {
734 
735   using namespace jitlink;
736 
737   bool InBootstrapPhase =
738       &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap;
739 
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);
746     });
747   }
748 
749   // --- Handle Initializers ---
750   if (auto InitSymbol = MR.getInitializerSymbol()) {
751 
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);
758       });
759       return;
760     }
761 
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
764     // sections/symbols.
765     Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
766       if (auto Err = preserveImportantSections(G, MR))
767         return Err;
768       return processObjCImageInfo(G, MR);
769     });
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); });
774   }
775 
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);
782       });
783 
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);
789       });
790 
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); });
796 }
797 
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);
807     return Result;
808   }
809   return SyntheticSymbolDependenciesMap();
810 }
811 
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();
818 }
819 
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}};
837 
838   bool RegisterMachOHeader = false;
839 
840   for (auto *Sym : G.defined_symbols()) {
841     for (auto &RTSym : RuntimeSymbols) {
842       if (Sym->hasName() && Sym->getName() == RTSym.first) {
843         if (*RTSym.second)
844           return make_error<StringError>(
845               "Duplicate " + RTSym.first +
846                   " detected during MachOPlatform bootstrap",
847               inconvertibleErrorCode());
848 
849         if (Sym->getName() == *MP.MachOHeaderStartSymbol)
850           RegisterMachOHeader = true;
851 
852         *RTSym.second = Sym->getAddress();
853       }
854     }
855   }
856 
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] =
864         &MP.PlatformJD;
865   }
866 
867   return Error::success();
868 }
869 
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();
880 }
881 
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;
886   });
887   assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
888 
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(
897       {cantFail(
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();
903 }
904 
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,
919                          true);
920 
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());
927   }
928 
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
935     // remove it later.
936     if (InitSectionName == MachOObjCImageInfoSectionName)
937       continue;
938 
939     // Skip non-init sections.
940     auto *InitSection = G.findSectionByName(InitSectionName);
941     if (!InitSection)
942       continue;
943 
944     // Make a pass over live symbols in the section: those blocks are already
945     // preserved.
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);
953       }
954     }
955 
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));
961   }
962 
963   if (!InitSectionSymbols.empty()) {
964     std::lock_guard<std::mutex> Lock(PluginMutex);
965     InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
966   }
967 
968   return Error::success();
969 }
970 
971 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
972     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
973 
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.
977   // OR
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);
981   if (!ObjCImageInfo)
982     return Error::success();
983 
984   auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
985 
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());
991 
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());
998 
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 " +
1009                                                G.getName(),
1010                                            inconvertibleErrorCode());
1011   }
1012 
1013   auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
1014   auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
1015   auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
1016   auto Flags =
1017       support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
1018 
1019   // Lock the mutex while we verify / update the ObjCImageInfos map.
1020   std::lock_guard<std::mutex> Lock(PluginMutex);
1021 
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());
1035 
1036     // __objc_imageinfo is valid. Delete the block.
1037     for (auto *S : ObjCImageInfo->symbols())
1038       G.removeDefinedSymbol(*S);
1039     G.removeBlock(ObjCImageInfoBlock);
1040   } else {
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()}}))
1049       return Err;
1050     ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags};
1051   }
1052 
1053   return Error::success();
1054 }
1055 
1056 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1057     jitlink::LinkGraph &G, JITDylib &JD) {
1058 
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");
1063       break;
1064     }
1065 
1066   // Store key in __thread_vars struct fields.
1067   if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) {
1068     std::optional<uint64_t> Key;
1069     {
1070       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1071       auto I = MP.JITDylibToPThreadKey.find(&JD);
1072       if (I != MP.JITDylibToPThreadKey.end())
1073         Key = I->second;
1074     }
1075 
1076     if (!Key) {
1077       if (auto KeyOrErr = MP.createPThreadKey())
1078         Key = *KeyOrErr;
1079       else
1080         return KeyOrErr.takeError();
1081     }
1082 
1083     uint64_t PlatformKeyBits =
1084         support::endian::byte_swap(*Key, G.getEndianness());
1085 
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());
1092 
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);
1098     }
1099   }
1100 
1101   // Transform any TLV edges into GOT edges.
1102   for (auto *B : G.blocks())
1103     for (auto &E : B->edges())
1104       if (E.getKind() ==
1105           jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
1106         E.setKind(jitlink::x86_64::
1107                       RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1108 
1109   return Error::success();
1110 }
1111 
1112 std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
1113 MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1114     jitlink::LinkGraph &G) {
1115   using namespace jitlink;
1116 
1117   UnwindSections US;
1118 
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())
1124       return;
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())
1132           continue;
1133         auto &TargetBlock = E.getTarget().getBlock();
1134         auto &TargetSection = TargetBlock.getSection();
1135         if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec)
1136           CodeBlocks.push_back(&TargetBlock);
1137       }
1138     }
1139   };
1140 
1141   if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName))
1142     ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection);
1143 
1144   if (Section *CUInfoSec =
1145           G.findSectionByName(MachOCompactUnwindInfoSectionName))
1146     ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection);
1147 
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;
1152 
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();
1157   });
1158   for (auto *B : CodeBlocks) {
1159     if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())
1160       US.CodeRanges.push_back(B->getRange());
1161     else
1162       US.CodeRanges.back().End = B->getRange().End;
1163   }
1164 
1165   LLVM_DEBUG({
1166     dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"
1167            << "  DWARF: ";
1168     if (US.DwarfSection.Start)
1169       dbgs() << US.DwarfSection << "\n";
1170     else
1171       dbgs() << "none\n";
1172     dbgs() << "  Compact-unwind: ";
1173     if (US.CompactUnwindSection.Start)
1174       dbgs() << US.CompactUnwindSection << "\n";
1175     else
1176       dbgs() << "none\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";
1183   });
1184 
1185   return US;
1186 }
1187 
1188 Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1189     jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) {
1190 
1191   // Get a pointer to the thread data section if there is one. It will be used
1192   // below.
1193   jitlink::Section *ThreadDataSection =
1194       G.findSectionByName(MachOThreadDataSectionName);
1195 
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);
1203     else
1204       ThreadDataSection = ThreadBSSSection;
1205   }
1206 
1207   SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
1208 
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);
1216       if (!R.empty())
1217         MachOPlatformSecs.push_back({SecName, R.getRange()});
1218     }
1219   }
1220 
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);
1225     if (!R.empty())
1226       MachOPlatformSecs.push_back({MachOThreadDataSectionName, R.getRange()});
1227   }
1228 
1229   // If any platform sections were found then add an allocation action to call
1230   // the registration function.
1231   StringRef PlatformSections[] = {MachOModInitFuncSectionName,
1232                                   ObjCRuntimeObjectSectionName};
1233 
1234   for (auto &SecName : PlatformSections) {
1235     auto *Sec = G.findSectionByName(SecName);
1236     if (!Sec)
1237       continue;
1238     jitlink::SectionRange R(*Sec);
1239     if (R.empty())
1240       continue;
1241 
1242     MachOPlatformSecs.push_back({SecName, R.getRange()});
1243   }
1244 
1245   std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1246                            ExecutorAddrRange>>
1247       UnwindInfo;
1248   if (auto UI = findUnwindSectionInfo(G))
1249     UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1250                                  UI->CompactUnwindSection);
1251 
1252   if (!MachOPlatformSecs.empty() || UnwindInfo) {
1253     ExecutorAddr HeaderAddr;
1254     {
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;
1260     }
1261 
1262     // Dump the scraped inits.
1263     LLVM_DEBUG({
1264       dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
1265       for (auto &KV : MachOPlatformSecs)
1266         dbgs() << "  " << KV.first << ": " << KV.second << "\n";
1267     });
1268 
1269     using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1270         SPSExecutorAddr,
1271         SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,
1272                              SPSExecutorAddrRange, SPSExecutorAddrRange>>,
1273         SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
1274 
1275     shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
1276                                              ? G.allocActions()
1277                                              : MP.Bootstrap.load()->DeferredAAs;
1278 
1279     allocActions.push_back(
1280         {cantFail(
1281              WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1282                  MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,
1283                  MachOPlatformSecs)),
1284          cantFail(
1285              WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1286                  MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,
1287                  UnwindInfo, MachOPlatformSecs))});
1288   }
1289 
1290   return Error::success();
1291 }
1292 
1293 Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
1294     jitlink::LinkGraph &G) {
1295 
1296   bool NeedTextSegment = false;
1297   size_t NumRuntimeSections = 0;
1298 
1299   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
1300     if (G.findSectionByName(ObjCRuntimeSectionName))
1301       ++NumRuntimeSections;
1302 
1303   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1304     if (G.findSectionByName(ObjCRuntimeSectionName)) {
1305       ++NumRuntimeSections;
1306       NeedTextSegment = true;
1307     }
1308   }
1309 
1310   // Early out for no runtime sections.
1311   if (NumRuntimeSections == 0)
1312     return Error::success();
1313 
1314   // If there were any runtime sections then we need to add an __objc_imageinfo
1315   // section.
1316   ++NumRuntimeSections;
1317 
1318   size_t MachOSize = sizeof(MachO::mach_header_64) +
1319                      (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
1320                      NumRuntimeSections * sizeof(MachO::section_64);
1321 
1322   auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
1323                               MemProt::Read | MemProt::Write);
1324   G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
1325 
1326   return Error::success();
1327 }
1328 
1329 Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
1330     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
1331 
1332   auto *ObjCRuntimeObjectSec =
1333       G.findSectionByName(ObjCRuntimeObjectSectionName);
1334 
1335   if (!ObjCRuntimeObjectSec)
1336     return Error::success();
1337 
1338   switch (G.getTargetTriple().getArch()) {
1339   case Triple::aarch64:
1340   case Triple::x86_64:
1341     // Supported.
1342     break;
1343   default:
1344     return make_error<StringError>("Unrecognized MachO arch in triple " +
1345                                        G.getTargetTriple().str(),
1346                                    inconvertibleErrorCode());
1347   }
1348 
1349   auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
1350 
1351   struct SecDesc {
1352     MachO::section_64 Sec;
1353     unique_function<void(size_t RecordOffset)> AddFixups;
1354   };
1355 
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;
1366   };
1367 
1368   // Add the __objc_imageinfo section.
1369   {
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");
1375     SD.Sec.size = 8;
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;
1381         break;
1382       case Triple::x86_64:
1383         PointerEdge = jitlink::x86_64::Pointer64;
1384         break;
1385       default:
1386         llvm_unreachable("Unsupported architecture");
1387       }
1388 
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;
1394           break;
1395         }
1396       if (!ObjCImageInfoSym)
1397         for (auto *Sym : G.absolute_symbols())
1398           if (Sym->getName() == ObjCImageInfoSymbolName) {
1399             ObjCImageInfoSym = Sym;
1400             break;
1401           }
1402       if (!ObjCImageInfoSym)
1403         for (auto *Sym : G.defined_symbols())
1404           if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) {
1405             ObjCImageInfoSym = Sym;
1406             break;
1407           }
1408       if (!ObjCImageInfoSym)
1409         ObjCImageInfoSym =
1410             &G.addExternalSymbol(ObjCImageInfoSymbolName, 8, false);
1411 
1412       SecBlock.addEdge(PointerEdge,
1413                        RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec),
1414                        *ObjCImageInfoSym, -SecBlock.getAddress().getValue());
1415     };
1416   }
1417 
1418   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
1419     if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1420       DataSections.push_back({});
1421       AddSection(DataSections.back(), *GraphSec);
1422     }
1423   }
1424 
1425   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1426     if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1427       TextSections.push_back({});
1428       AddSection(TextSections.back(), *GraphSec);
1429     }
1430   }
1431 
1432   assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
1433          "Unexpected number of blocks in runtime sections object");
1434 
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;
1443     break;
1444   case Triple::x86_64:
1445     Hdr.cputype = MachO::CPU_TYPE_X86_64;
1446     Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
1447     break;
1448   default:
1449     llvm_unreachable("Unsupported architecture");
1450   }
1451 
1452   Hdr.filetype = MachO::MH_DYLIB;
1453   Hdr.ncmds = 1 + !TextSections.empty();
1454   Hdr.sizeofcmds =
1455       Hdr.ncmds * sizeof(MachO::segment_command_64) +
1456       (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);
1457   Hdr.flags = 0;
1458   Hdr.reserved = 0;
1459 
1460   auto SecContent = SecBlock.getAlreadyMutableContent();
1461   char *P = SecContent.data();
1462   auto WriteMachOStruct = [&](auto S) {
1463     if (G.getEndianness() != support::endian::system_endianness())
1464       MachO::swapStruct(S);
1465     memcpy(P, &S, sizeof(S));
1466     P += sizeof(S);
1467   };
1468 
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) {
1479       if (SD.AddFixups)
1480         SD.AddFixups(P - SecContent.data());
1481       WriteMachOStruct(SD.Sec);
1482     }
1483   };
1484 
1485   WriteMachOStruct(Hdr);
1486   if (!TextSections.empty())
1487     WriteSegment("__TEXT", TextSections);
1488   if (!DataSections.empty())
1489     WriteSegment("__DATA", DataSections);
1490 
1491   assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
1492   return Error::success();
1493 }
1494 
1495 } // End namespace orc.
1496 } // End namespace llvm.
1497