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/Support/BinaryByteStream.h"
16 #include "llvm/Support/Debug.h"
17 
18 #define DEBUG_TYPE "orc"
19 
20 using namespace llvm;
21 using namespace llvm::orc;
22 using namespace llvm::orc::shared;
23 
24 namespace {
25 
26 class MachOHeaderMaterializationUnit : public MaterializationUnit {
27 public:
28   MachOHeaderMaterializationUnit(MachOPlatform &MOP,
29                                  const SymbolStringPtr &HeaderStartSymbol)
30       : MaterializationUnit(createHeaderSymbols(MOP, HeaderStartSymbol),
31                             HeaderStartSymbol),
32         MOP(MOP) {}
33 
34   StringRef getName() const override { return "MachOHeaderMU"; }
35 
36   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
37     unsigned PointerSize;
38     support::endianness Endianness;
39 
40     switch (MOP.getExecutorProcessControl().getTargetTriple().getArch()) {
41     case Triple::aarch64:
42     case Triple::x86_64:
43       PointerSize = 8;
44       Endianness = support::endianness::little;
45       break;
46     default:
47       llvm_unreachable("Unrecognized architecture");
48     }
49 
50     auto G = std::make_unique<jitlink::LinkGraph>(
51         "<MachOHeaderMU>", MOP.getExecutorProcessControl().getTargetTriple(),
52         PointerSize, Endianness, jitlink::getGenericEdgeKindName);
53     auto &HeaderSection = G->createSection("__header", sys::Memory::MF_READ);
54     auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
55 
56     // Init symbol is header-start symbol.
57     G->addDefinedSymbol(HeaderBlock, 0, *R->getInitializerSymbol(),
58                         HeaderBlock.getSize(), jitlink::Linkage::Strong,
59                         jitlink::Scope::Default, false, true);
60     for (auto &HS : AdditionalHeaderSymbols)
61       G->addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name,
62                           HeaderBlock.getSize(), jitlink::Linkage::Strong,
63                           jitlink::Scope::Default, false, true);
64 
65     MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
66   }
67 
68   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
69 
70 private:
71   struct HeaderSymbol {
72     const char *Name;
73     uint64_t Offset;
74   };
75 
76   static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
77       {"___mh_executable_header", 0}};
78 
79   static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
80                                            jitlink::Section &HeaderSection) {
81     MachO::mach_header_64 Hdr;
82     Hdr.magic = MachO::MH_MAGIC_64;
83     switch (G.getTargetTriple().getArch()) {
84     case Triple::aarch64:
85       Hdr.cputype = MachO::CPU_TYPE_ARM64;
86       Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
87       break;
88     case Triple::x86_64:
89       Hdr.cputype = MachO::CPU_TYPE_X86_64;
90       Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
91       break;
92     default:
93       llvm_unreachable("Unrecognized architecture");
94     }
95     Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
96     Hdr.ncmds = 0;
97     Hdr.sizeofcmds = 0;
98     Hdr.flags = 0;
99     Hdr.reserved = 0;
100 
101     if (G.getEndianness() != support::endian::system_endianness())
102       MachO::swapStruct(Hdr);
103 
104     auto HeaderContent = G.allocateString(
105         StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
106 
107     return G.createContentBlock(HeaderSection, HeaderContent, 0, 8, 0);
108   }
109 
110   static SymbolFlagsMap
111   createHeaderSymbols(MachOPlatform &MOP,
112                       const SymbolStringPtr &HeaderStartSymbol) {
113     SymbolFlagsMap HeaderSymbolFlags;
114 
115     HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
116     for (auto &HS : AdditionalHeaderSymbols)
117       HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
118           JITSymbolFlags::Exported;
119 
120     return HeaderSymbolFlags;
121   }
122 
123   MachOPlatform &MOP;
124 };
125 
126 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
127     MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
128 
129 StringRef EHFrameSectionName = "__TEXT,__eh_frame";
130 StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
131 
132 StringRef InitSectionNames[] = {ModInitFuncSectionName};
133 
134 } // end anonymous namespace
135 
136 namespace llvm {
137 namespace orc {
138 
139 Expected<std::unique_ptr<MachOPlatform>>
140 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
141                       ExecutorProcessControl &EPC, JITDylib &PlatformJD,
142                       const char *OrcRuntimePath,
143                       Optional<SymbolAliasMap> RuntimeAliases) {
144 
145   // If the target is not supported then bail out immediately.
146   if (!supportedTarget(EPC.getTargetTriple()))
147     return make_error<StringError>("Unsupported MachOPlatform triple: " +
148                                        EPC.getTargetTriple().str(),
149                                    inconvertibleErrorCode());
150 
151   // Create default aliases if the caller didn't supply any.
152   if (!RuntimeAliases)
153     RuntimeAliases = standardPlatformAliases(ES);
154 
155   // Define the aliases.
156   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
157     return std::move(Err);
158 
159   // Add JIT-dispatch function support symbols.
160   if (auto Err = PlatformJD.define(absoluteSymbols(
161           {{ES.intern("___orc_rt_jit_dispatch"),
162             {EPC.getJITDispatchInfo().JITDispatchFunctionAddress.getValue(),
163              JITSymbolFlags::Exported}},
164            {ES.intern("___orc_rt_jit_dispatch_ctx"),
165             {EPC.getJITDispatchInfo().JITDispatchContextAddress.getValue(),
166              JITSymbolFlags::Exported}}})))
167     return std::move(Err);
168 
169   // Create a generator for the ORC runtime archive.
170   auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
171       ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
172   if (!OrcRuntimeArchiveGenerator)
173     return OrcRuntimeArchiveGenerator.takeError();
174 
175   // Create the instance.
176   Error Err = Error::success();
177   auto P = std::unique_ptr<MachOPlatform>(
178       new MachOPlatform(ES, ObjLinkingLayer, EPC, PlatformJD,
179                         std::move(*OrcRuntimeArchiveGenerator), Err));
180   if (Err)
181     return std::move(Err);
182   return std::move(P);
183 }
184 
185 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
186   return JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
187       *this, MachOHeaderStartSymbol));
188 }
189 
190 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
191                                   const MaterializationUnit &MU) {
192   auto &JD = RT.getJITDylib();
193   const auto &InitSym = MU.getInitializerSymbol();
194   if (!InitSym)
195     return Error::success();
196 
197   RegisteredInitSymbols[&JD].add(InitSym,
198                                  SymbolLookupFlags::WeaklyReferencedSymbol);
199   LLVM_DEBUG({
200     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
201            << MU.getName() << "\n";
202   });
203   return Error::success();
204 }
205 
206 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
207   llvm_unreachable("Not supported yet");
208 }
209 
210 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
211                        ArrayRef<std::pair<const char *, const char *>> AL) {
212   for (auto &KV : AL) {
213     auto AliasName = ES.intern(KV.first);
214     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
215     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
216                                      JITSymbolFlags::Exported};
217   }
218 }
219 
220 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
221   SymbolAliasMap Aliases;
222   addAliases(ES, Aliases, requiredCXXAliases());
223   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
224   return Aliases;
225 }
226 
227 ArrayRef<std::pair<const char *, const char *>>
228 MachOPlatform::requiredCXXAliases() {
229   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
230       {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
231 
232   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
233 }
234 
235 ArrayRef<std::pair<const char *, const char *>>
236 MachOPlatform::standardRuntimeUtilityAliases() {
237   static const std::pair<const char *, const char *>
238       StandardRuntimeUtilityAliases[] = {
239           {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
240           {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
241 
242   return ArrayRef<std::pair<const char *, const char *>>(
243       StandardRuntimeUtilityAliases);
244 }
245 
246 bool MachOPlatform::supportedTarget(const Triple &TT) {
247   switch (TT.getArch()) {
248   case Triple::x86_64:
249     return true;
250   default:
251     return false;
252   }
253 }
254 
255 MachOPlatform::MachOPlatform(
256     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
257     ExecutorProcessControl &EPC, JITDylib &PlatformJD,
258     std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
259     : ES(ES), ObjLinkingLayer(ObjLinkingLayer), EPC(EPC),
260       MachOHeaderStartSymbol(ES.intern("___dso_handle")) {
261   ErrorAsOutParameter _(&Err);
262 
263   ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
264 
265   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
266 
267   // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
268   // the platform now), so set it up.
269   if (auto E2 = setupJITDylib(PlatformJD)) {
270     Err = std::move(E2);
271     return;
272   }
273 
274   RegisteredInitSymbols[&PlatformJD].add(
275       MachOHeaderStartSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);
276 
277   // Associate wrapper function tags with JIT-side function implementations.
278   if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
279     Err = std::move(E2);
280     return;
281   }
282 
283   // Lookup addresses of runtime functions callable by the platform,
284   // call the platform bootstrap function to initialize the platform-state
285   // object in the executor.
286   if (auto E2 = bootstrapMachORuntime(PlatformJD)) {
287     Err = std::move(E2);
288     return;
289   }
290 }
291 
292 Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
293   ExecutorProcessControl::WrapperFunctionAssociationMap WFs;
294 
295   using GetInitializersSPSSig =
296       SPSExpected<SPSMachOJITDylibInitializerSequence>(SPSString);
297   WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] =
298       EPC.wrapAsyncWithSPS<GetInitializersSPSSig>(
299           this, &MachOPlatform::rt_getInitializers);
300 
301   using GetDeinitializersSPSSig =
302       SPSExpected<SPSMachOJITDylibDeinitializerSequence>(SPSExecutorAddress);
303   WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] =
304       EPC.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
305           this, &MachOPlatform::rt_getDeinitializers);
306 
307   using LookupSymbolSPSSig =
308       SPSExpected<SPSExecutorAddress>(SPSExecutorAddress, SPSString);
309   WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
310       EPC.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
311                                                &MachOPlatform::rt_lookupSymbol);
312 
313   return EPC.associateJITSideWrapperFunctions(PlatformJD, std::move(WFs));
314 }
315 
316 void MachOPlatform::getInitializersBuildSequencePhase(
317     SendInitializerSequenceFn SendResult, JITDylib &JD,
318     std::vector<JITDylibSP> DFSLinkOrder) {
319   MachOJITDylibInitializerSequence FullInitSeq;
320   {
321     std::lock_guard<std::mutex> Lock(PlatformMutex);
322     for (auto &InitJD : reverse(DFSLinkOrder)) {
323       LLVM_DEBUG({
324         dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName()
325                << "\" to sequence\n";
326       });
327       auto ISItr = InitSeqs.find(InitJD.get());
328       if (ISItr != InitSeqs.end()) {
329         FullInitSeq.emplace_back(std::move(ISItr->second));
330         InitSeqs.erase(ISItr);
331       }
332     }
333   }
334 
335   SendResult(std::move(FullInitSeq));
336 }
337 
338 void MachOPlatform::getInitializersLookupPhase(
339     SendInitializerSequenceFn SendResult, JITDylib &JD) {
340 
341   auto DFSLinkOrder = JD.getDFSLinkOrder();
342   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
343   ES.runSessionLocked([&]() {
344     for (auto &InitJD : DFSLinkOrder) {
345       auto RISItr = RegisteredInitSymbols.find(InitJD.get());
346       if (RISItr != RegisteredInitSymbols.end()) {
347         NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
348         RegisteredInitSymbols.erase(RISItr);
349       }
350     }
351   });
352 
353   // If there are no further init symbols to look up then move on to the next
354   // phase.
355   if (NewInitSymbols.empty()) {
356     getInitializersBuildSequencePhase(std::move(SendResult), JD,
357                                       std::move(DFSLinkOrder));
358     return;
359   }
360 
361   // Otherwise issue a lookup and re-run this phase when it completes.
362   lookupInitSymbolsAsync(
363       [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
364         if (Err)
365           SendResult(std::move(Err));
366         else
367           getInitializersLookupPhase(std::move(SendResult), JD);
368       },
369       ES, std::move(NewInitSymbols));
370 }
371 
372 void MachOPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
373                                        StringRef JDName) {
374   LLVM_DEBUG({
375     dbgs() << "MachOPlatform::rt_getInitializers(\"" << JDName << "\")\n";
376   });
377 
378   JITDylib *JD = ES.getJITDylibByName(JDName);
379   if (!JD) {
380     LLVM_DEBUG({
381       dbgs() << "  No such JITDylib \"" << JDName << "\". Sending error.\n";
382     });
383     SendResult(make_error<StringError>("No JITDylib named " + JDName,
384                                        inconvertibleErrorCode()));
385     return;
386   }
387 
388   getInitializersLookupPhase(std::move(SendResult), *JD);
389 }
390 
391 void MachOPlatform::rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
392                                          ExecutorAddress Handle) {
393   LLVM_DEBUG({
394     dbgs() << "MachOPlatform::rt_getDeinitializers(\""
395            << formatv("{0:x}", Handle.getValue()) << "\")\n";
396   });
397 
398   JITDylib *JD = nullptr;
399 
400   {
401     std::lock_guard<std::mutex> Lock(PlatformMutex);
402     auto I = HeaderAddrToJITDylib.find(Handle.getValue());
403     if (I != HeaderAddrToJITDylib.end())
404       JD = I->second;
405   }
406 
407   if (!JD) {
408     LLVM_DEBUG({
409       dbgs() << "  No JITDylib for handle "
410              << formatv("{0:x}", Handle.getValue()) << "\n";
411     });
412     SendResult(make_error<StringError>("No JITDylib associated with handle " +
413                                            formatv("{0:x}", Handle.getValue()),
414                                        inconvertibleErrorCode()));
415     return;
416   }
417 
418   SendResult(MachOJITDylibDeinitializerSequence());
419 }
420 
421 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
422                                     ExecutorAddress Handle,
423                                     StringRef SymbolName) {
424   LLVM_DEBUG({
425     dbgs() << "MachOPlatform::rt_lookupSymbol(\""
426            << formatv("{0:x}", Handle.getValue()) << "\")\n";
427   });
428 
429   JITDylib *JD = nullptr;
430 
431   {
432     std::lock_guard<std::mutex> Lock(PlatformMutex);
433     auto I = HeaderAddrToJITDylib.find(Handle.getValue());
434     if (I != HeaderAddrToJITDylib.end())
435       JD = I->second;
436   }
437 
438   if (!JD) {
439     LLVM_DEBUG({
440       dbgs() << "  No JITDylib for handle "
441              << formatv("{0:x}", Handle.getValue()) << "\n";
442     });
443     SendResult(make_error<StringError>("No JITDylib associated with handle " +
444                                            formatv("{0:x}", Handle.getValue()),
445                                        inconvertibleErrorCode()));
446     return;
447   }
448 
449   // FIXME: Proper mangling.
450   auto MangledName = ("_" + SymbolName).str();
451   ES.lookup(
452       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
453       SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
454       [SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable {
455         if (Result) {
456           assert(Result->size() == 1 && "Unexpected result map count");
457           SendResult(ExecutorAddress(Result->begin()->second.getAddress()));
458         } else
459           SendResult(Result.takeError());
460       },
461       NoDependenciesToRegister);
462 }
463 
464 Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) {
465 
466   std::pair<const char *, ExecutorAddress *> Symbols[] = {
467       {"___orc_rt_macho_platform_bootstrap", &orc_rt_macho_platform_bootstrap},
468       {"___orc_rt_macho_platform_shutdown", &orc_rt_macho_platform_shutdown},
469       {"___orc_rt_macho_register_object_sections",
470        &orc_rt_macho_register_object_sections}};
471 
472   SymbolLookupSet RuntimeSymbols;
473   std::vector<std::pair<SymbolStringPtr, ExecutorAddress *>> AddrsToRecord;
474   for (const auto &KV : Symbols) {
475     auto Name = ES.intern(KV.first);
476     RuntimeSymbols.add(Name);
477     AddrsToRecord.push_back({std::move(Name), KV.second});
478   }
479 
480   auto RuntimeSymbolAddrs = ES.lookup(
481       {{&PlatformJD, JITDylibLookupFlags::MatchAllSymbols}}, RuntimeSymbols);
482   if (!RuntimeSymbolAddrs)
483     return RuntimeSymbolAddrs.takeError();
484 
485   for (const auto &KV : AddrsToRecord) {
486     auto &Name = KV.first;
487     assert(RuntimeSymbolAddrs->count(Name) && "Missing runtime symbol?");
488     KV.second->setValue((*RuntimeSymbolAddrs)[Name].getAddress());
489   }
490 
491   if (auto Err =
492           EPC.runSPSWrapper<void()>(orc_rt_macho_platform_bootstrap.getValue()))
493     return Err;
494 
495   // FIXME: Ordering is fuzzy here. We're probably best off saying
496   // "behavior is undefined if code that uses the runtime is added before
497   // the platform constructor returns", then move all this to the constructor.
498   RuntimeBootstrapped = true;
499   std::vector<MachOPerObjectSectionsToRegister> DeferredPOSRs;
500   {
501     std::lock_guard<std::mutex> Lock(PlatformMutex);
502     DeferredPOSRs = std::move(BootstrapPOSRs);
503   }
504 
505   for (auto &D : DeferredPOSRs)
506     if (auto Err = registerPerObjectSections(D))
507       return Err;
508 
509   return Error::success();
510 }
511 
512 Error MachOPlatform::registerInitInfo(
513     JITDylib &JD, ArrayRef<jitlink::Section *> InitSections) {
514 
515   std::unique_lock<std::mutex> Lock(PlatformMutex);
516 
517   MachOJITDylibInitializers *InitSeq = nullptr;
518   {
519     auto I = InitSeqs.find(&JD);
520     if (I == InitSeqs.end()) {
521       // If there's no init sequence entry yet then we need to look up the
522       // header symbol to force creation of one.
523       Lock.unlock();
524 
525       auto SearchOrder =
526           JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
527       if (auto Err = ES.lookup(SearchOrder, MachOHeaderStartSymbol).takeError())
528         return Err;
529 
530       Lock.lock();
531       I = InitSeqs.find(&JD);
532       assert(I != InitSeqs.end() &&
533              "Entry missing after header symbol lookup?");
534     }
535     InitSeq = &I->second;
536   }
537 
538   for (auto *Sec : InitSections) {
539     // FIXME: Avoid copy here.
540     jitlink::SectionRange R(*Sec);
541     InitSeq->InitSections[Sec->getName()].push_back(
542         {ExecutorAddress(R.getStart()), ExecutorAddress(R.getEnd())});
543   }
544 
545   return Error::success();
546 }
547 
548 Error MachOPlatform::registerPerObjectSections(
549     const MachOPerObjectSectionsToRegister &POSR) {
550 
551   if (!orc_rt_macho_register_object_sections)
552     return make_error<StringError>("Attempting to register per-object "
553                                    "sections, but runtime support has not "
554                                    "been loaded yet",
555                                    inconvertibleErrorCode());
556 
557   Error ErrResult = Error::success();
558   if (auto Err = EPC.runSPSWrapper<shared::SPSError(
559                      SPSMachOPerObjectSectionsToRegister)>(
560           orc_rt_macho_register_object_sections.getValue(), ErrResult, POSR))
561     return Err;
562   return ErrResult;
563 }
564 
565 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
566     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
567     jitlink::PassConfiguration &Config) {
568 
569   // If the initializer symbol is the MachOHeader start symbol then just add
570   // the macho header support passes.
571   if (MR.getInitializerSymbol() == MP.MachOHeaderStartSymbol) {
572     addMachOHeaderSupportPasses(MR, Config);
573     // The header materialization unit doesn't require any other support, so we
574     // can bail out early.
575     return;
576   }
577 
578   // If the object contains initializers then add passes to record them.
579   if (MR.getInitializerSymbol())
580     addInitializerSupportPasses(MR, Config);
581 
582   // Add passes for eh-frame support.
583   addEHSupportPasses(MR, Config);
584 }
585 
586 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
587 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
588     MaterializationResponsibility &MR) {
589   std::lock_guard<std::mutex> Lock(PluginMutex);
590   auto I = InitSymbolDeps.find(&MR);
591   if (I != InitSymbolDeps.end()) {
592     SyntheticSymbolDependenciesMap Result;
593     Result[MR.getInitializerSymbol()] = std::move(I->second);
594     InitSymbolDeps.erase(&MR);
595     return Result;
596   }
597   return SyntheticSymbolDependenciesMap();
598 }
599 
600 void MachOPlatform::MachOPlatformPlugin::addInitializerSupportPasses(
601     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
602 
603   /// Preserve init sections.
604   Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
605     return preserveInitSections(G, MR);
606   });
607 
608   Config.PostFixupPasses.push_back(
609       [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
610         return registerInitSections(G, JD);
611       });
612 }
613 
614 void MachOPlatform::MachOPlatformPlugin::addMachOHeaderSupportPasses(
615     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
616 
617   Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib()](
618                                             jitlink::LinkGraph &G) -> Error {
619     auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
620       return Sym->getName() == *MP.MachOHeaderStartSymbol;
621     });
622     assert(I != G.defined_symbols().end() &&
623            "Missing MachO header start symbol");
624     {
625       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
626       JITTargetAddress HeaderAddr = (*I)->getAddress();
627       MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
628       assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists");
629       MP.InitSeqs.insert(
630           std::make_pair(&JD, MachOJITDylibInitializers(
631                                   JD.getName(), ExecutorAddress(HeaderAddr))));
632     }
633     return Error::success();
634   });
635 }
636 
637 void MachOPlatform::MachOPlatformPlugin::addEHSupportPasses(
638     MaterializationResponsibility &MR, jitlink::PassConfiguration &Config) {
639 
640   // Add a pass to register the final addresses of the eh-frame sections
641   // with the runtime.
642   Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
643     MachOPerObjectSectionsToRegister POSR;
644 
645     if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) {
646       jitlink::SectionRange R(*EHFrameSection);
647       if (!R.empty())
648         POSR.EHFrameSection = {ExecutorAddress(R.getStart()),
649                                ExecutorAddress(R.getEnd())};
650     }
651 
652     if (POSR.EHFrameSection.StartAddress) {
653 
654       // If we're still bootstrapping the runtime then just record this
655       // frame for now.
656       if (!MP.RuntimeBootstrapped) {
657         std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
658         MP.BootstrapPOSRs.push_back(POSR);
659         return Error::success();
660       }
661 
662       // Otherwise register it immediately.
663       if (auto Err = MP.registerPerObjectSections(POSR))
664         return Err;
665     }
666 
667     return Error::success();
668   });
669 }
670 
671 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
672     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
673 
674   JITLinkSymbolSet InitSectionSymbols;
675   for (auto &InitSectionName : InitSectionNames) {
676     // Skip non-init sections.
677     auto *InitSection = G.findSectionByName(InitSectionName);
678     if (!InitSection)
679       continue;
680 
681     // Make a pass over live symbols in the section: those blocks are already
682     // preserved.
683     DenseSet<jitlink::Block *> AlreadyLiveBlocks;
684     for (auto &Sym : InitSection->symbols()) {
685       auto &B = Sym->getBlock();
686       if (Sym->isLive() && Sym->getOffset() == 0 &&
687           Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
688         InitSectionSymbols.insert(Sym);
689         AlreadyLiveBlocks.insert(&B);
690       }
691     }
692 
693     // Add anonymous symbols to preserve any not-already-preserved blocks.
694     for (auto *B : InitSection->blocks())
695       if (!AlreadyLiveBlocks.count(B))
696         InitSectionSymbols.insert(
697             &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
698   }
699 
700   if (!InitSectionSymbols.empty()) {
701     std::lock_guard<std::mutex> Lock(PluginMutex);
702     InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
703   }
704 
705   return Error::success();
706 }
707 
708 Error MachOPlatform::MachOPlatformPlugin::registerInitSections(
709     jitlink::LinkGraph &G, JITDylib &JD) {
710 
711   SmallVector<jitlink::Section *> InitSections;
712 
713   for (auto InitSectionName : InitSectionNames)
714     if (auto *Sec = G.findSectionByName(InitSectionName))
715       InitSections.push_back(Sec);
716 
717   // Dump the scraped inits.
718   LLVM_DEBUG({
719     dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
720     for (auto *Sec : InitSections) {
721       jitlink::SectionRange R(*Sec);
722       dbgs() << "  " << Sec->getName() << ": "
723              << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n";
724     }
725   });
726 
727   return MP.registerInitInfo(JD, InitSections);
728 }
729 
730 } // End namespace orc.
731 } // End namespace llvm.
732