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 
19 #define DEBUG_TYPE "orc"
20 
21 using namespace llvm;
22 using namespace llvm::orc;
23 using namespace llvm::orc::shared;
24 
25 namespace {
26 
27 class MachOHeaderMaterializationUnit : public MaterializationUnit {
28 public:
29   MachOHeaderMaterializationUnit(MachOPlatform &MOP,
30                                  const SymbolStringPtr &HeaderStartSymbol)
31       : MaterializationUnit(createHeaderInterface(MOP, 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     const auto &TT =
40         MOP.getExecutionSession().getExecutorProcessControl().getTargetTriple();
41 
42     switch (TT.getArch()) {
43     case Triple::aarch64:
44     case Triple::x86_64:
45       PointerSize = 8;
46       Endianness = support::endianness::little;
47       break;
48     default:
49       llvm_unreachable("Unrecognized architecture");
50     }
51 
52     auto G = std::make_unique<jitlink::LinkGraph>(
53         "<MachOHeaderMU>", TT, PointerSize, Endianness,
54         jitlink::getGenericEdgeKindName);
55     auto &HeaderSection = G->createSection("__header", jitlink::MemProt::Read);
56     auto &HeaderBlock = createHeaderBlock(*G, HeaderSection);
57 
58     // Init symbol is header-start symbol.
59     G->addDefinedSymbol(HeaderBlock, 0, *R->getInitializerSymbol(),
60                         HeaderBlock.getSize(), jitlink::Linkage::Strong,
61                         jitlink::Scope::Default, false, true);
62     for (auto &HS : AdditionalHeaderSymbols)
63       G->addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name,
64                           HeaderBlock.getSize(), jitlink::Linkage::Strong,
65                           jitlink::Scope::Default, false, true);
66 
67     MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
68   }
69 
70   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
71 
72 private:
73   struct HeaderSymbol {
74     const char *Name;
75     uint64_t Offset;
76   };
77 
78   static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
79       {"___mh_executable_header", 0}};
80 
81   static jitlink::Block &createHeaderBlock(jitlink::LinkGraph &G,
82                                            jitlink::Section &HeaderSection) {
83     MachO::mach_header_64 Hdr;
84     Hdr.magic = MachO::MH_MAGIC_64;
85     switch (G.getTargetTriple().getArch()) {
86     case Triple::aarch64:
87       Hdr.cputype = MachO::CPU_TYPE_ARM64;
88       Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
89       break;
90     case Triple::x86_64:
91       Hdr.cputype = MachO::CPU_TYPE_X86_64;
92       Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
93       break;
94     default:
95       llvm_unreachable("Unrecognized architecture");
96     }
97     Hdr.filetype = MachO::MH_DYLIB; // Custom file type?
98     Hdr.ncmds = 0;
99     Hdr.sizeofcmds = 0;
100     Hdr.flags = 0;
101     Hdr.reserved = 0;
102 
103     if (G.getEndianness() != support::endian::system_endianness())
104       MachO::swapStruct(Hdr);
105 
106     auto HeaderContent = G.allocateString(
107         StringRef(reinterpret_cast<const char *>(&Hdr), sizeof(Hdr)));
108 
109     return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
110                                 0);
111   }
112 
113   static MaterializationUnit::Interface
114   createHeaderInterface(MachOPlatform &MOP,
115                         const SymbolStringPtr &HeaderStartSymbol) {
116     SymbolFlagsMap HeaderSymbolFlags;
117 
118     HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
119     for (auto &HS : AdditionalHeaderSymbols)
120       HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
121           JITSymbolFlags::Exported;
122 
123     return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
124                                           HeaderStartSymbol);
125   }
126 
127   MachOPlatform &MOP;
128 };
129 
130 constexpr MachOHeaderMaterializationUnit::HeaderSymbol
131     MachOHeaderMaterializationUnit::AdditionalHeaderSymbols[];
132 
133 StringRef EHFrameSectionName = "__TEXT,__eh_frame";
134 StringRef ModInitFuncSectionName = "__DATA,__mod_init_func";
135 StringRef ObjCClassListSectionName = "__DATA,__objc_classlist";
136 StringRef ObjCImageInfoSectionName = "__DATA,__objc_image_info";
137 StringRef ObjCSelRefsSectionName = "__DATA,__objc_selrefs";
138 StringRef Swift5ProtoSectionName = "__TEXT,__swift5_proto";
139 StringRef Swift5ProtosSectionName = "__TEXT,__swift5_protos";
140 StringRef Swift5TypesSectionName = "__TEXT,__swift5_types";
141 StringRef ThreadBSSSectionName = "__DATA,__thread_bss";
142 StringRef ThreadDataSectionName = "__DATA,__thread_data";
143 StringRef ThreadVarsSectionName = "__DATA,__thread_vars";
144 
145 StringRef InitSectionNames[] = {
146     ModInitFuncSectionName, ObjCSelRefsSectionName, ObjCClassListSectionName,
147     Swift5ProtosSectionName, Swift5ProtoSectionName, Swift5TypesSectionName};
148 
149 } // end anonymous namespace
150 
151 namespace llvm {
152 namespace orc {
153 
154 Expected<std::unique_ptr<MachOPlatform>>
155 MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
156                       JITDylib &PlatformJD, const char *OrcRuntimePath,
157                       Optional<SymbolAliasMap> RuntimeAliases) {
158 
159   auto &EPC = ES.getExecutorProcessControl();
160 
161   // If the target is not supported then bail out immediately.
162   if (!supportedTarget(EPC.getTargetTriple()))
163     return make_error<StringError>("Unsupported MachOPlatform triple: " +
164                                        EPC.getTargetTriple().str(),
165                                    inconvertibleErrorCode());
166 
167   // Create default aliases if the caller didn't supply any.
168   if (!RuntimeAliases)
169     RuntimeAliases = standardPlatformAliases(ES);
170 
171   // Define the aliases.
172   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
173     return std::move(Err);
174 
175   // Add JIT-dispatch function support symbols.
176   if (auto Err = PlatformJD.define(absoluteSymbols(
177           {{ES.intern("___orc_rt_jit_dispatch"),
178             {EPC.getJITDispatchInfo().JITDispatchFunction.getValue(),
179              JITSymbolFlags::Exported}},
180            {ES.intern("___orc_rt_jit_dispatch_ctx"),
181             {EPC.getJITDispatchInfo().JITDispatchContext.getValue(),
182              JITSymbolFlags::Exported}}})))
183     return std::move(Err);
184 
185   // Create a generator for the ORC runtime archive.
186   auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Load(
187       ObjLinkingLayer, OrcRuntimePath, EPC.getTargetTriple());
188   if (!OrcRuntimeArchiveGenerator)
189     return OrcRuntimeArchiveGenerator.takeError();
190 
191   // Create the instance.
192   Error Err = Error::success();
193   auto P = std::unique_ptr<MachOPlatform>(
194       new MachOPlatform(ES, ObjLinkingLayer, PlatformJD,
195                         std::move(*OrcRuntimeArchiveGenerator), Err));
196   if (Err)
197     return std::move(Err);
198   return std::move(P);
199 }
200 
201 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
202   return JD.define(std::make_unique<MachOHeaderMaterializationUnit>(
203       *this, MachOHeaderStartSymbol));
204 }
205 
206 Error MachOPlatform::teardownJITDylib(JITDylib &JD) { return Error::success(); }
207 
208 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
209                                   const MaterializationUnit &MU) {
210   auto &JD = RT.getJITDylib();
211   const auto &InitSym = MU.getInitializerSymbol();
212   if (!InitSym)
213     return Error::success();
214 
215   RegisteredInitSymbols[&JD].add(InitSym,
216                                  SymbolLookupFlags::WeaklyReferencedSymbol);
217   LLVM_DEBUG({
218     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
219            << MU.getName() << "\n";
220   });
221   return Error::success();
222 }
223 
224 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
225   llvm_unreachable("Not supported yet");
226 }
227 
228 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
229                        ArrayRef<std::pair<const char *, const char *>> AL) {
230   for (auto &KV : AL) {
231     auto AliasName = ES.intern(KV.first);
232     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
233     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
234                                      JITSymbolFlags::Exported};
235   }
236 }
237 
238 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
239   SymbolAliasMap Aliases;
240   addAliases(ES, Aliases, requiredCXXAliases());
241   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
242   return Aliases;
243 }
244 
245 ArrayRef<std::pair<const char *, const char *>>
246 MachOPlatform::requiredCXXAliases() {
247   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
248       {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
249 
250   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
251 }
252 
253 ArrayRef<std::pair<const char *, const char *>>
254 MachOPlatform::standardRuntimeUtilityAliases() {
255   static const std::pair<const char *, const char *>
256       StandardRuntimeUtilityAliases[] = {
257           {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
258           {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
259 
260   return ArrayRef<std::pair<const char *, const char *>>(
261       StandardRuntimeUtilityAliases);
262 }
263 
264 bool MachOPlatform::isInitializerSection(StringRef SegName,
265                                          StringRef SectName) {
266   for (auto &Name : InitSectionNames) {
267     if (Name.startswith(SegName) && Name.substr(7) == SectName)
268       return true;
269   }
270   return false;
271 }
272 
273 bool MachOPlatform::supportedTarget(const Triple &TT) {
274   switch (TT.getArch()) {
275   case Triple::aarch64:
276   case Triple::x86_64:
277     return true;
278   default:
279     return false;
280   }
281 }
282 
283 MachOPlatform::MachOPlatform(
284     ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
285     JITDylib &PlatformJD,
286     std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
287     : ES(ES), ObjLinkingLayer(ObjLinkingLayer),
288       MachOHeaderStartSymbol(ES.intern("___dso_handle")) {
289   ErrorAsOutParameter _(&Err);
290 
291   ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
292 
293   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
294 
295   // Force linking of eh-frame registration functions.
296   if (auto Err2 = lookupAndRecordAddrs(
297           ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
298           {{ES.intern("___orc_rt_macho_register_ehframe_section"),
299             &orc_rt_macho_register_ehframe_section},
300            {ES.intern("___orc_rt_macho_deregister_ehframe_section"),
301             &orc_rt_macho_deregister_ehframe_section}})) {
302     Err = std::move(Err2);
303     return;
304   }
305 
306   State = BootstrapPhase2;
307 
308   // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating
309   // the platform now), so set it up.
310   if (auto E2 = setupJITDylib(PlatformJD)) {
311     Err = std::move(E2);
312     return;
313   }
314 
315   RegisteredInitSymbols[&PlatformJD].add(
316       MachOHeaderStartSymbol, SymbolLookupFlags::WeaklyReferencedSymbol);
317 
318   // Associate wrapper function tags with JIT-side function implementations.
319   if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) {
320     Err = std::move(E2);
321     return;
322   }
323 
324   // Lookup addresses of runtime functions callable by the platform,
325   // call the platform bootstrap function to initialize the platform-state
326   // object in the executor.
327   if (auto E2 = bootstrapMachORuntime(PlatformJD)) {
328     Err = std::move(E2);
329     return;
330   }
331 
332   State = Initialized;
333 }
334 
335 Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) {
336   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
337 
338   using GetInitializersSPSSig =
339       SPSExpected<SPSMachOJITDylibInitializerSequence>(SPSString);
340   WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] =
341       ES.wrapAsyncWithSPS<GetInitializersSPSSig>(
342           this, &MachOPlatform::rt_getInitializers);
343 
344   using GetDeinitializersSPSSig =
345       SPSExpected<SPSMachOJITDylibDeinitializerSequence>(SPSExecutorAddr);
346   WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] =
347       ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>(
348           this, &MachOPlatform::rt_getDeinitializers);
349 
350   using LookupSymbolSPSSig =
351       SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString);
352   WFs[ES.intern("___orc_rt_macho_symbol_lookup_tag")] =
353       ES.wrapAsyncWithSPS<LookupSymbolSPSSig>(this,
354                                               &MachOPlatform::rt_lookupSymbol);
355 
356   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
357 }
358 
359 void MachOPlatform::getInitializersBuildSequencePhase(
360     SendInitializerSequenceFn SendResult, JITDylib &JD,
361     std::vector<JITDylibSP> DFSLinkOrder) {
362   MachOJITDylibInitializerSequence FullInitSeq;
363   {
364     std::lock_guard<std::mutex> Lock(PlatformMutex);
365     for (auto &InitJD : reverse(DFSLinkOrder)) {
366       LLVM_DEBUG({
367         dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName()
368                << "\" to sequence\n";
369       });
370       auto ISItr = InitSeqs.find(InitJD.get());
371       if (ISItr != InitSeqs.end()) {
372         FullInitSeq.emplace_back(std::move(ISItr->second));
373         InitSeqs.erase(ISItr);
374       }
375     }
376   }
377 
378   SendResult(std::move(FullInitSeq));
379 }
380 
381 void MachOPlatform::getInitializersLookupPhase(
382     SendInitializerSequenceFn SendResult, JITDylib &JD) {
383 
384   auto DFSLinkOrder = JD.getDFSLinkOrder();
385   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
386   ES.runSessionLocked([&]() {
387     for (auto &InitJD : DFSLinkOrder) {
388       auto RISItr = RegisteredInitSymbols.find(InitJD.get());
389       if (RISItr != RegisteredInitSymbols.end()) {
390         NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
391         RegisteredInitSymbols.erase(RISItr);
392       }
393     }
394   });
395 
396   // If there are no further init symbols to look up then move on to the next
397   // phase.
398   if (NewInitSymbols.empty()) {
399     getInitializersBuildSequencePhase(std::move(SendResult), JD,
400                                       std::move(DFSLinkOrder));
401     return;
402   }
403 
404   // Otherwise issue a lookup and re-run this phase when it completes.
405   lookupInitSymbolsAsync(
406       [this, SendResult = std::move(SendResult), &JD](Error Err) mutable {
407         if (Err)
408           SendResult(std::move(Err));
409         else
410           getInitializersLookupPhase(std::move(SendResult), JD);
411       },
412       ES, std::move(NewInitSymbols));
413 }
414 
415 void MachOPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult,
416                                        StringRef JDName) {
417   LLVM_DEBUG({
418     dbgs() << "MachOPlatform::rt_getInitializers(\"" << JDName << "\")\n";
419   });
420 
421   JITDylib *JD = ES.getJITDylibByName(JDName);
422   if (!JD) {
423     LLVM_DEBUG({
424       dbgs() << "  No such JITDylib \"" << JDName << "\". Sending error.\n";
425     });
426     SendResult(make_error<StringError>("No JITDylib named " + JDName,
427                                        inconvertibleErrorCode()));
428     return;
429   }
430 
431   getInitializersLookupPhase(std::move(SendResult), *JD);
432 }
433 
434 void MachOPlatform::rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
435                                          ExecutorAddr Handle) {
436   LLVM_DEBUG({
437     dbgs() << "MachOPlatform::rt_getDeinitializers(\""
438            << formatv("{0:x}", Handle.getValue()) << "\")\n";
439   });
440 
441   JITDylib *JD = nullptr;
442 
443   {
444     std::lock_guard<std::mutex> Lock(PlatformMutex);
445     auto I = HeaderAddrToJITDylib.find(Handle);
446     if (I != HeaderAddrToJITDylib.end())
447       JD = I->second;
448   }
449 
450   if (!JD) {
451     LLVM_DEBUG({
452       dbgs() << "  No JITDylib for handle "
453              << formatv("{0:x}", Handle.getValue()) << "\n";
454     });
455     SendResult(make_error<StringError>("No JITDylib associated with handle " +
456                                            formatv("{0:x}", Handle.getValue()),
457                                        inconvertibleErrorCode()));
458     return;
459   }
460 
461   SendResult(MachOJITDylibDeinitializerSequence());
462 }
463 
464 void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult,
465                                     ExecutorAddr Handle, StringRef SymbolName) {
466   LLVM_DEBUG({
467     dbgs() << "MachOPlatform::rt_lookupSymbol(\""
468            << formatv("{0:x}", Handle.getValue()) << "\")\n";
469   });
470 
471   JITDylib *JD = nullptr;
472 
473   {
474     std::lock_guard<std::mutex> Lock(PlatformMutex);
475     auto I = HeaderAddrToJITDylib.find(Handle);
476     if (I != HeaderAddrToJITDylib.end())
477       JD = I->second;
478   }
479 
480   if (!JD) {
481     LLVM_DEBUG({
482       dbgs() << "  No JITDylib for handle "
483              << formatv("{0:x}", Handle.getValue()) << "\n";
484     });
485     SendResult(make_error<StringError>("No JITDylib associated with handle " +
486                                            formatv("{0:x}", Handle.getValue()),
487                                        inconvertibleErrorCode()));
488     return;
489   }
490 
491   // Use functor class to work around XL build compiler issue on AIX.
492   class RtLookupNotifyComplete {
493   public:
494     RtLookupNotifyComplete(SendSymbolAddressFn &&SendResult)
495         : SendResult(std::move(SendResult)) {}
496     void operator()(Expected<SymbolMap> Result) {
497       if (Result) {
498         assert(Result->size() == 1 && "Unexpected result map count");
499         SendResult(ExecutorAddr(Result->begin()->second.getAddress()));
500       } else {
501         SendResult(Result.takeError());
502       }
503     }
504 
505   private:
506     SendSymbolAddressFn SendResult;
507   };
508 
509   // FIXME: Proper mangling.
510   auto MangledName = ("_" + SymbolName).str();
511   ES.lookup(
512       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
513       SymbolLookupSet(ES.intern(MangledName)), SymbolState::Ready,
514       RtLookupNotifyComplete(std::move(SendResult)), NoDependenciesToRegister);
515 }
516 
517 Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) {
518   if (auto Err = lookupAndRecordAddrs(
519           ES, LookupKind::Static, makeJITDylibSearchOrder(&PlatformJD),
520           {{ES.intern("___orc_rt_macho_platform_bootstrap"),
521             &orc_rt_macho_platform_bootstrap},
522            {ES.intern("___orc_rt_macho_platform_shutdown"),
523             &orc_rt_macho_platform_shutdown},
524            {ES.intern("___orc_rt_macho_register_thread_data_section"),
525             &orc_rt_macho_register_thread_data_section},
526            {ES.intern("___orc_rt_macho_deregister_thread_data_section"),
527             &orc_rt_macho_deregister_thread_data_section},
528            {ES.intern("___orc_rt_macho_create_pthread_key"),
529             &orc_rt_macho_create_pthread_key}}))
530     return Err;
531 
532   return ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap);
533 }
534 
535 Error MachOPlatform::registerInitInfo(
536     JITDylib &JD, ExecutorAddr ObjCImageInfoAddr,
537     ArrayRef<jitlink::Section *> InitSections) {
538 
539   std::unique_lock<std::mutex> Lock(PlatformMutex);
540 
541   MachOJITDylibInitializers *InitSeq = nullptr;
542   {
543     auto I = InitSeqs.find(&JD);
544     if (I == InitSeqs.end()) {
545       // If there's no init sequence entry yet then we need to look up the
546       // header symbol to force creation of one.
547       Lock.unlock();
548 
549       auto SearchOrder =
550           JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; });
551       if (auto Err = ES.lookup(SearchOrder, MachOHeaderStartSymbol).takeError())
552         return Err;
553 
554       Lock.lock();
555       I = InitSeqs.find(&JD);
556       assert(I != InitSeqs.end() &&
557              "Entry missing after header symbol lookup?");
558     }
559     InitSeq = &I->second;
560   }
561 
562   InitSeq->ObjCImageInfoAddress = ObjCImageInfoAddr;
563 
564   for (auto *Sec : InitSections) {
565     // FIXME: Avoid copy here.
566     jitlink::SectionRange R(*Sec);
567     InitSeq->InitSections[Sec->getName()].push_back(
568         {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())});
569   }
570 
571   return Error::success();
572 }
573 
574 Expected<uint64_t> MachOPlatform::createPThreadKey() {
575   if (!orc_rt_macho_create_pthread_key)
576     return make_error<StringError>(
577         "Attempting to create pthread key in target, but runtime support has "
578         "not been loaded yet",
579         inconvertibleErrorCode());
580 
581   Expected<uint64_t> Result(0);
582   if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
583           orc_rt_macho_create_pthread_key, Result))
584     return std::move(Err);
585   return Result;
586 }
587 
588 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
589     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
590     jitlink::PassConfiguration &Config) {
591 
592   auto PS = MP.State.load();
593 
594   // --- Handle Initializers ---
595   if (auto InitSymbol = MR.getInitializerSymbol()) {
596 
597     // If the initializer symbol is the MachOHeader start symbol then just
598     // register it and then bail out -- the header materialization unit
599     // definitely doesn't need any other passes.
600     if (InitSymbol == MP.MachOHeaderStartSymbol) {
601       Config.PostAllocationPasses.push_back([this, &MR](jitlink::LinkGraph &G) {
602         return associateJITDylibHeaderSymbol(G, MR);
603       });
604       return;
605     }
606 
607     // If the object contains an init symbol other than the header start symbol
608     // then add passes to preserve, process and register the init
609     // sections/symbols.
610     Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) {
611       if (auto Err = preserveInitSections(G, MR))
612         return Err;
613       return processObjCImageInfo(G, MR);
614     });
615 
616     Config.PostFixupPasses.push_back(
617         [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
618           return registerInitSections(G, JD);
619         });
620   }
621 
622   // --- Add passes for eh-frame and TLV support ---
623   if (PS == MachOPlatform::BootstrapPhase1) {
624     Config.PostFixupPasses.push_back(
625         [this](jitlink::LinkGraph &G) { return registerEHSectionsPhase1(G); });
626     return;
627   }
628 
629   // Insert TLV lowering at the start of the PostPrunePasses, since we want
630   // it to run before GOT/PLT lowering.
631   Config.PostPrunePasses.insert(
632       Config.PostPrunePasses.begin(),
633       [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) {
634         return fixTLVSectionsAndEdges(G, JD);
635       });
636 
637   // Add a pass to register the final addresses of the eh-frame and TLV sections
638   // with the runtime.
639   Config.PostFixupPasses.push_back(
640       [this](jitlink::LinkGraph &G) { return registerEHAndTLVSections(G); });
641 }
642 
643 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap
644 MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies(
645     MaterializationResponsibility &MR) {
646   std::lock_guard<std::mutex> Lock(PluginMutex);
647   auto I = InitSymbolDeps.find(&MR);
648   if (I != InitSymbolDeps.end()) {
649     SyntheticSymbolDependenciesMap Result;
650     Result[MR.getInitializerSymbol()] = std::move(I->second);
651     InitSymbolDeps.erase(&MR);
652     return Result;
653   }
654   return SyntheticSymbolDependenciesMap();
655 }
656 
657 Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
658     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
659 
660   auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
661     return Sym->getName() == *MP.MachOHeaderStartSymbol;
662   });
663   assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
664 
665   auto &JD = MR.getTargetJITDylib();
666   std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
667   auto HeaderAddr = (*I)->getAddress();
668   MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
669   assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists");
670   MP.InitSeqs.insert(
671       std::make_pair(&JD, MachOJITDylibInitializers(JD.getName(), HeaderAddr)));
672   return Error::success();
673 }
674 
675 Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
676     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
677 
678   JITLinkSymbolSet InitSectionSymbols;
679   for (auto &InitSectionName : InitSectionNames) {
680     // Skip non-init sections.
681     auto *InitSection = G.findSectionByName(InitSectionName);
682     if (!InitSection)
683       continue;
684 
685     // Make a pass over live symbols in the section: those blocks are already
686     // preserved.
687     DenseSet<jitlink::Block *> AlreadyLiveBlocks;
688     for (auto &Sym : InitSection->symbols()) {
689       auto &B = Sym->getBlock();
690       if (Sym->isLive() && Sym->getOffset() == 0 &&
691           Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
692         InitSectionSymbols.insert(Sym);
693         AlreadyLiveBlocks.insert(&B);
694       }
695     }
696 
697     // Add anonymous symbols to preserve any not-already-preserved blocks.
698     for (auto *B : InitSection->blocks())
699       if (!AlreadyLiveBlocks.count(B))
700         InitSectionSymbols.insert(
701             &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
702   }
703 
704   if (!InitSectionSymbols.empty()) {
705     std::lock_guard<std::mutex> Lock(PluginMutex);
706     InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
707   }
708 
709   return Error::success();
710 }
711 
712 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
713     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
714 
715   // If there's an ObjC imagine info then either
716   //   (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
717   //       this case we name and record it.
718   // OR
719   //   (2) We already have a recorded __objc_imageinfo for this JITDylib,
720   //       in which case we just verify it.
721   auto *ObjCImageInfo = G.findSectionByName(ObjCImageInfoSectionName);
722   if (!ObjCImageInfo)
723     return Error::success();
724 
725   auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
726 
727   // Check that the section is not empty if present.
728   if (llvm::empty(ObjCImageInfoBlocks))
729     return make_error<StringError>("Empty " + ObjCImageInfoSectionName +
730                                        " section in " + G.getName(),
731                                    inconvertibleErrorCode());
732 
733   // Check that there's only one block in the section.
734   if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
735     return make_error<StringError>("Multiple blocks in " +
736                                        ObjCImageInfoSectionName +
737                                        " section in " + G.getName(),
738                                    inconvertibleErrorCode());
739 
740   // Check that the __objc_imageinfo section is unreferenced.
741   // FIXME: We could optimize this check if Symbols had a ref-count.
742   for (auto &Sec : G.sections()) {
743     if (&Sec != ObjCImageInfo)
744       for (auto *B : Sec.blocks())
745         for (auto &E : B->edges())
746           if (E.getTarget().isDefined() &&
747               &E.getTarget().getBlock().getSection() == ObjCImageInfo)
748             return make_error<StringError>(ObjCImageInfoSectionName +
749                                                " is referenced within file " +
750                                                G.getName(),
751                                            inconvertibleErrorCode());
752   }
753 
754   auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
755   auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
756   auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
757   auto Flags =
758       support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
759 
760   // Lock the mutex while we verify / update the ObjCImageInfos map.
761   std::lock_guard<std::mutex> Lock(PluginMutex);
762 
763   auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
764   if (ObjCImageInfoItr != ObjCImageInfos.end()) {
765     // We've already registered an __objc_imageinfo section. Verify the
766     // content of this new section matches, then delete it.
767     if (ObjCImageInfoItr->second.first != Version)
768       return make_error<StringError>(
769           "ObjC version in " + G.getName() +
770               " does not match first registered version",
771           inconvertibleErrorCode());
772     if (ObjCImageInfoItr->second.second != Flags)
773       return make_error<StringError>("ObjC flags in " + G.getName() +
774                                          " do not match first registered flags",
775                                      inconvertibleErrorCode());
776 
777     // __objc_imageinfo is valid. Delete the block.
778     for (auto *S : ObjCImageInfo->symbols())
779       G.removeDefinedSymbol(*S);
780     G.removeBlock(ObjCImageInfoBlock);
781   } else {
782     // We haven't registered an __objc_imageinfo section yet. Register and
783     // move on. The section should already be marked no-dead-strip.
784     ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
785   }
786 
787   return Error::success();
788 }
789 
790 Error MachOPlatform::MachOPlatformPlugin::registerInitSections(
791     jitlink::LinkGraph &G, JITDylib &JD) {
792 
793   ExecutorAddr ObjCImageInfoAddr;
794   SmallVector<jitlink::Section *> InitSections;
795 
796   if (auto *ObjCImageInfoSec = G.findSectionByName(ObjCImageInfoSectionName)) {
797     if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart())
798       ObjCImageInfoAddr = Addr;
799   }
800 
801   for (auto InitSectionName : InitSectionNames)
802     if (auto *Sec = G.findSectionByName(InitSectionName))
803       InitSections.push_back(Sec);
804 
805   // Dump the scraped inits.
806   LLVM_DEBUG({
807     dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
808     if (ObjCImageInfoAddr)
809       dbgs() << "  " << ObjCImageInfoSectionName << ": "
810              << formatv("{0:x}", ObjCImageInfoAddr.getValue()) << "\n";
811     for (auto *Sec : InitSections) {
812       jitlink::SectionRange R(*Sec);
813       dbgs() << "  " << Sec->getName() << ": "
814              << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n";
815     }
816   });
817 
818   return MP.registerInitInfo(JD, ObjCImageInfoAddr, InitSections);
819 }
820 
821 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
822     jitlink::LinkGraph &G, JITDylib &JD) {
823 
824   // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
825   for (auto *Sym : G.external_symbols())
826     if (Sym->getName() == "__tlv_bootstrap") {
827       Sym->setName("___orc_rt_macho_tlv_get_addr");
828       break;
829     }
830 
831   // Store key in __thread_vars struct fields.
832   if (auto *ThreadDataSec = G.findSectionByName(ThreadVarsSectionName)) {
833     Optional<uint64_t> Key;
834     {
835       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
836       auto I = MP.JITDylibToPThreadKey.find(&JD);
837       if (I != MP.JITDylibToPThreadKey.end())
838         Key = I->second;
839     }
840 
841     if (!Key) {
842       if (auto KeyOrErr = MP.createPThreadKey())
843         Key = *KeyOrErr;
844       else
845         return KeyOrErr.takeError();
846     }
847 
848     uint64_t PlatformKeyBits =
849         support::endian::byte_swap(*Key, G.getEndianness());
850 
851     for (auto *B : ThreadDataSec->blocks()) {
852       if (B->getSize() != 3 * G.getPointerSize())
853         return make_error<StringError>("__thread_vars block at " +
854                                            formatv("{0:x}", B->getAddress()) +
855                                            " has unexpected size",
856                                        inconvertibleErrorCode());
857 
858       auto NewBlockContent = G.allocateBuffer(B->getSize());
859       llvm::copy(B->getContent(), NewBlockContent.data());
860       memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
861              G.getPointerSize());
862       B->setContent(NewBlockContent);
863     }
864   }
865 
866   // Transform any TLV edges into GOT edges.
867   for (auto *B : G.blocks())
868     for (auto &E : B->edges())
869       if (E.getKind() ==
870           jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
871         E.setKind(jitlink::x86_64::
872                       RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
873 
874   return Error::success();
875 }
876 
877 Error MachOPlatform::MachOPlatformPlugin::registerEHAndTLVSections(
878     jitlink::LinkGraph &G) {
879 
880   // Add a pass to register the final addresses of the eh-frame and TLV sections
881   // with the runtime.
882   if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) {
883     jitlink::SectionRange R(*EHFrameSection);
884     if (!R.empty())
885       G.allocActions().push_back(
886           {cantFail(
887                WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
888                    MP.orc_rt_macho_register_ehframe_section, R.getRange())),
889            cantFail(
890                WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
891                    MP.orc_rt_macho_deregister_ehframe_section, R.getRange()))});
892   }
893 
894   // Get a pointer to the thread data section if there is one. It will be used
895   // below.
896   jitlink::Section *ThreadDataSection =
897       G.findSectionByName(ThreadDataSectionName);
898 
899   // Handle thread BSS section if there is one.
900   if (auto *ThreadBSSSection = G.findSectionByName(ThreadBSSSectionName)) {
901     // If there's already a thread data section in this graph then merge the
902     // thread BSS section content into it, otherwise just treat the thread
903     // BSS section as the thread data section.
904     if (ThreadDataSection)
905       G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
906     else
907       ThreadDataSection = ThreadBSSSection;
908   }
909 
910   // Having merged thread BSS (if present) and thread data (if present),
911   // record the resulting section range.
912   if (ThreadDataSection) {
913     jitlink::SectionRange R(*ThreadDataSection);
914     if (!R.empty()) {
915       if (MP.State != MachOPlatform::Initialized)
916         return make_error<StringError>("__thread_data section encountered, but "
917                                        "MachOPlatform has not finished booting",
918                                        inconvertibleErrorCode());
919 
920       G.allocActions().push_back(
921           {cantFail(
922                WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
923                    MP.orc_rt_macho_register_thread_data_section, R.getRange())),
924            cantFail(
925                WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
926                    MP.orc_rt_macho_deregister_thread_data_section,
927                    R.getRange()))});
928     }
929   }
930   return Error::success();
931 }
932 
933 Error MachOPlatform::MachOPlatformPlugin::registerEHSectionsPhase1(
934     jitlink::LinkGraph &G) {
935 
936   // If there's no eh-frame there's nothing to do.
937   auto *EHFrameSection = G.findSectionByName(EHFrameSectionName);
938   if (!EHFrameSection)
939     return Error::success();
940 
941   // If the eh-frame section is empty there's nothing to do.
942   jitlink::SectionRange R(*EHFrameSection);
943   if (R.empty())
944     return Error::success();
945 
946   // Since we're linking the object containing the registration code now the
947   // addresses won't be ready in the platform. We'll have to find them in this
948   // graph instead.
949   ExecutorAddr orc_rt_macho_register_ehframe_section;
950   ExecutorAddr orc_rt_macho_deregister_ehframe_section;
951   for (auto *Sym : G.defined_symbols()) {
952     if (!Sym->hasName())
953       continue;
954     if (Sym->getName() == "___orc_rt_macho_register_ehframe_section")
955       orc_rt_macho_register_ehframe_section = ExecutorAddr(Sym->getAddress());
956     else if (Sym->getName() == "___orc_rt_macho_deregister_ehframe_section")
957       orc_rt_macho_deregister_ehframe_section = ExecutorAddr(Sym->getAddress());
958 
959     if (orc_rt_macho_register_ehframe_section &&
960         orc_rt_macho_deregister_ehframe_section)
961       break;
962   }
963 
964   // If we failed to find the required functions then bail out.
965   if (!orc_rt_macho_register_ehframe_section ||
966       !orc_rt_macho_deregister_ehframe_section)
967     return make_error<StringError>("Could not find eh-frame registration "
968                                    "functions during platform bootstrap",
969                                    inconvertibleErrorCode());
970 
971   // Otherwise, add allocation actions to the graph to register eh-frames for
972   // this object.
973   G.allocActions().push_back(
974       {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
975            orc_rt_macho_register_ehframe_section, R.getRange())),
976        cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
977            orc_rt_macho_deregister_ehframe_section, R.getRange()))});
978 
979   return Error::success();
980 }
981 
982 } // End namespace orc.
983 } // End namespace llvm.
984