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