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