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