xref: /freebsd/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp (revision 79d939126a819f31882343b5733c2073452a4218)
1 //===- macho_platform.cpp -------------------------------------------------===//
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 // This file contains code required to load the rest of the MachO runtime.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "macho_platform.h"
14 #include "common.h"
15 #include "error.h"
16 #include "wrapper_function_utils.h"
17 
18 #include <map>
19 #include <mutex>
20 #include <sstream>
21 #include <unordered_map>
22 #include <vector>
23 
24 using namespace __orc_rt;
25 using namespace __orc_rt::macho;
26 
27 // Declare function tags for functions in the JIT process.
28 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_get_initializers_tag)
29 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_get_deinitializers_tag)
30 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
31 
32 // Objective-C types.
33 struct objc_class;
34 struct objc_image_info;
35 struct objc_object;
36 struct objc_selector;
37 
38 using Class = objc_class *;
39 using id = objc_object *;
40 using SEL = objc_selector *;
41 
42 // Objective-C registration functions.
43 // These are weakly imported. If the Objective-C runtime has not been loaded
44 // then code containing Objective-C sections will generate an error.
45 extern "C" id objc_msgSend(id, SEL, ...) ORC_RT_WEAK_IMPORT;
46 extern "C" Class objc_readClassPair(Class,
47                                     const objc_image_info *) ORC_RT_WEAK_IMPORT;
48 extern "C" SEL sel_registerName(const char *) ORC_RT_WEAK_IMPORT;
49 
50 // Swift types.
51 class ProtocolRecord;
52 class ProtocolConformanceRecord;
53 class TypeMetadataRecord;
54 
55 extern "C" void
56 swift_registerProtocols(const ProtocolRecord *begin,
57                         const ProtocolRecord *end) ORC_RT_WEAK_IMPORT;
58 
59 extern "C" void swift_registerProtocolConformances(
60     const ProtocolConformanceRecord *begin,
61     const ProtocolConformanceRecord *end) ORC_RT_WEAK_IMPORT;
62 
63 extern "C" void swift_registerTypeMetadataRecords(
64     const TypeMetadataRecord *begin,
65     const TypeMetadataRecord *end) ORC_RT_WEAK_IMPORT;
66 
67 namespace {
68 
69 Error validatePointerSectionExtent(const char *SectionName,
70                                    const ExecutorAddrRange &SE) {
71   if (SE.size().getValue() % sizeof(uintptr_t)) {
72     std::ostringstream ErrMsg;
73     ErrMsg << std::hex << "Size of " << SectionName << " 0x"
74            << SE.Start.getValue() << " -- 0x" << SE.End.getValue()
75            << " is not a pointer multiple";
76     return make_error<StringError>(ErrMsg.str());
77   }
78   return Error::success();
79 }
80 
81 Error registerObjCSelectors(
82     const std::vector<ExecutorAddrRange> &ObjCSelRefsSections,
83     const MachOJITDylibInitializers &MOJDIs) {
84 
85   if (ORC_RT_UNLIKELY(!sel_registerName))
86     return make_error<StringError>("sel_registerName is not available");
87 
88   for (const auto &ObjCSelRefs : ObjCSelRefsSections) {
89 
90     if (auto Err = validatePointerSectionExtent("__objc_selrefs", ObjCSelRefs))
91       return Err;
92 
93     for (uintptr_t &SelEntry : ObjCSelRefs.toSpan<uintptr_t>()) {
94       const char *SelName = reinterpret_cast<const char *>(SelEntry);
95       auto Sel = sel_registerName(SelName);
96       *reinterpret_cast<SEL *>(&SelEntry) = Sel;
97     }
98   }
99 
100   return Error::success();
101 }
102 
103 Error registerObjCClasses(
104     const std::vector<ExecutorAddrRange> &ObjCClassListSections,
105     const MachOJITDylibInitializers &MOJDIs) {
106 
107   if (ObjCClassListSections.empty())
108     return Error::success();
109 
110   if (ORC_RT_UNLIKELY(!objc_msgSend))
111     return make_error<StringError>("objc_msgSend is not available");
112   if (ORC_RT_UNLIKELY(!objc_readClassPair))
113     return make_error<StringError>("objc_readClassPair is not available");
114 
115   struct ObjCClassCompiled {
116     void *Metaclass;
117     void *Parent;
118     void *Cache1;
119     void *Cache2;
120     void *Data;
121   };
122 
123   auto *ImageInfo =
124       MOJDIs.ObjCImageInfoAddress.toPtr<const objc_image_info *>();
125   auto ClassSelector = sel_registerName("class");
126 
127   for (const auto &ObjCClassList : ObjCClassListSections) {
128 
129     if (auto Err =
130             validatePointerSectionExtent("__objc_classlist", ObjCClassList))
131       return Err;
132 
133     for (uintptr_t ClassPtr : ObjCClassList.toSpan<uintptr_t>()) {
134       auto *Cls = reinterpret_cast<Class>(ClassPtr);
135       auto *ClassCompiled = reinterpret_cast<ObjCClassCompiled *>(ClassPtr);
136       objc_msgSend(reinterpret_cast<id>(ClassCompiled->Parent), ClassSelector);
137       auto Registered = objc_readClassPair(Cls, ImageInfo);
138 
139       // FIXME: Improve diagnostic by reporting the failed class's name.
140       if (Registered != Cls)
141         return make_error<StringError>("Unable to register Objective-C class");
142     }
143   }
144   return Error::success();
145 }
146 
147 Error registerSwift5Protocols(
148     const std::vector<ExecutorAddrRange> &Swift5ProtocolSections,
149     const MachOJITDylibInitializers &MOJDIs) {
150 
151   if (ORC_RT_UNLIKELY(!Swift5ProtocolSections.empty() &&
152                       !swift_registerProtocols))
153     return make_error<StringError>("swift_registerProtocols is not available");
154 
155   for (const auto &Swift5Protocols : Swift5ProtocolSections)
156     swift_registerProtocols(
157         Swift5Protocols.Start.toPtr<const ProtocolRecord *>(),
158         Swift5Protocols.End.toPtr<const ProtocolRecord *>());
159 
160   return Error::success();
161 }
162 
163 Error registerSwift5ProtocolConformances(
164     const std::vector<ExecutorAddrRange> &Swift5ProtocolConformanceSections,
165     const MachOJITDylibInitializers &MOJDIs) {
166 
167   if (ORC_RT_UNLIKELY(!Swift5ProtocolConformanceSections.empty() &&
168                       !swift_registerProtocolConformances))
169     return make_error<StringError>(
170         "swift_registerProtocolConformances is not available");
171 
172   for (const auto &ProtoConfSec : Swift5ProtocolConformanceSections)
173     swift_registerProtocolConformances(
174         ProtoConfSec.Start.toPtr<const ProtocolConformanceRecord *>(),
175         ProtoConfSec.End.toPtr<const ProtocolConformanceRecord *>());
176 
177   return Error::success();
178 }
179 
180 Error registerSwift5Types(const std::vector<ExecutorAddrRange> &Sections,
181                           const MachOJITDylibInitializers &MOJDIs) {
182 
183   if (ORC_RT_UNLIKELY(!Sections.empty() && !swift_registerTypeMetadataRecords))
184     return make_error<StringError>(
185         "swift_registerTypeMetadataRecords is not available");
186 
187   for (const auto &Section : Sections)
188     swift_registerTypeMetadataRecords(
189         Section.Start.toPtr<const TypeMetadataRecord *>(),
190         Section.End.toPtr<const TypeMetadataRecord *>());
191 
192   return Error::success();
193 }
194 
195 Error runModInits(const std::vector<ExecutorAddrRange> &ModInitsSections,
196                   const MachOJITDylibInitializers &MOJDIs) {
197 
198   for (const auto &ModInits : ModInitsSections) {
199     if (auto Err = validatePointerSectionExtent("__mod_inits", ModInits))
200       return Err;
201 
202     using InitFunc = void (*)();
203     for (auto *Init : ModInits.toSpan<InitFunc>())
204       (*Init)();
205   }
206 
207   return Error::success();
208 }
209 
210 struct TLVDescriptor {
211   void *(*Thunk)(TLVDescriptor *) = nullptr;
212   unsigned long Key = 0;
213   unsigned long DataAddress = 0;
214 };
215 
216 class MachOPlatformRuntimeState {
217 private:
218   struct AtExitEntry {
219     void (*Func)(void *);
220     void *Arg;
221   };
222 
223   using AtExitsVector = std::vector<AtExitEntry>;
224 
225   struct PerJITDylibState {
226     void *Header = nullptr;
227     size_t RefCount = 0;
228     bool AllowReinitialization = false;
229     AtExitsVector AtExits;
230   };
231 
232 public:
233   static void initialize();
234   static MachOPlatformRuntimeState &get();
235   static void destroy();
236 
237   MachOPlatformRuntimeState() = default;
238 
239   // Delete copy and move constructors.
240   MachOPlatformRuntimeState(const MachOPlatformRuntimeState &) = delete;
241   MachOPlatformRuntimeState &
242   operator=(const MachOPlatformRuntimeState &) = delete;
243   MachOPlatformRuntimeState(MachOPlatformRuntimeState &&) = delete;
244   MachOPlatformRuntimeState &operator=(MachOPlatformRuntimeState &&) = delete;
245 
246   Error registerThreadDataSection(span<const char> ThreadDataSec);
247   Error deregisterThreadDataSection(span<const char> ThreadDataSec);
248 
249   const char *dlerror();
250   void *dlopen(string_view Name, int Mode);
251   int dlclose(void *DSOHandle);
252   void *dlsym(void *DSOHandle, string_view Symbol);
253 
254   int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
255   void runAtExits(void *DSOHandle);
256 
257   /// Returns the base address of the section containing ThreadData.
258   Expected<std::pair<const char *, size_t>>
259   getThreadDataSectionFor(const char *ThreadData);
260 
261 private:
262   PerJITDylibState *getJITDylibStateByHeaderAddr(void *DSOHandle);
263   PerJITDylibState *getJITDylibStateByName(string_view Path);
264   PerJITDylibState &getOrCreateJITDylibState(MachOJITDylibInitializers &MOJDIs);
265 
266   Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle,
267                                                 string_view Symbol);
268 
269   Expected<MachOJITDylibInitializerSequence>
270   getJITDylibInitializersByName(string_view Path);
271   Expected<void *> dlopenInitialize(string_view Path, int Mode);
272   Error initializeJITDylib(MachOJITDylibInitializers &MOJDIs);
273 
274   static MachOPlatformRuntimeState *MOPS;
275 
276   using InitSectionHandler =
277       Error (*)(const std::vector<ExecutorAddrRange> &Sections,
278                 const MachOJITDylibInitializers &MOJDIs);
279   const std::vector<std::pair<const char *, InitSectionHandler>> InitSections =
280       {{"__DATA,__objc_selrefs", registerObjCSelectors},
281        {"__DATA,__objc_classlist", registerObjCClasses},
282        {"__TEXT,__swift5_protos", registerSwift5Protocols},
283        {"__TEXT,__swift5_proto", registerSwift5ProtocolConformances},
284        {"__TEXT,__swift5_types", registerSwift5Types},
285        {"__DATA,__mod_init_func", runModInits}};
286 
287   // FIXME: Move to thread-state.
288   std::string DLFcnError;
289 
290   std::recursive_mutex JDStatesMutex;
291   std::unordered_map<void *, PerJITDylibState> JDStates;
292   std::unordered_map<std::string, void *> JDNameToHeader;
293 
294   std::mutex ThreadDataSectionsMutex;
295   std::map<const char *, size_t> ThreadDataSections;
296 };
297 
298 MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr;
299 
300 void MachOPlatformRuntimeState::initialize() {
301   assert(!MOPS && "MachOPlatformRuntimeState should be null");
302   MOPS = new MachOPlatformRuntimeState();
303 }
304 
305 MachOPlatformRuntimeState &MachOPlatformRuntimeState::get() {
306   assert(MOPS && "MachOPlatformRuntimeState not initialized");
307   return *MOPS;
308 }
309 
310 void MachOPlatformRuntimeState::destroy() {
311   assert(MOPS && "MachOPlatformRuntimeState not initialized");
312   delete MOPS;
313 }
314 
315 Error MachOPlatformRuntimeState::registerThreadDataSection(
316     span<const char> ThreadDataSection) {
317   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
318   auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
319   if (I != ThreadDataSections.begin()) {
320     auto J = std::prev(I);
321     if (J->first + J->second > ThreadDataSection.data())
322       return make_error<StringError>("Overlapping __thread_data sections");
323   }
324   ThreadDataSections.insert(
325       I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
326   return Error::success();
327 }
328 
329 Error MachOPlatformRuntimeState::deregisterThreadDataSection(
330     span<const char> ThreadDataSection) {
331   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
332   auto I = ThreadDataSections.find(ThreadDataSection.data());
333   if (I == ThreadDataSections.end())
334     return make_error<StringError>("Attempt to deregister unknown thread data "
335                                    "section");
336   ThreadDataSections.erase(I);
337   return Error::success();
338 }
339 
340 const char *MachOPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
341 
342 void *MachOPlatformRuntimeState::dlopen(string_view Path, int Mode) {
343   std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
344 
345   // Use fast path if all JITDylibs are already loaded and don't require
346   // re-running initializers.
347   if (auto *JDS = getJITDylibStateByName(Path)) {
348     if (!JDS->AllowReinitialization) {
349       ++JDS->RefCount;
350       return JDS->Header;
351     }
352   }
353 
354   auto H = dlopenInitialize(Path, Mode);
355   if (!H) {
356     DLFcnError = toString(H.takeError());
357     return nullptr;
358   }
359 
360   return *H;
361 }
362 
363 int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
364   runAtExits(DSOHandle);
365   return 0;
366 }
367 
368 void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, string_view Symbol) {
369   auto Addr = lookupSymbolInJITDylib(DSOHandle, Symbol);
370   if (!Addr) {
371     DLFcnError = toString(Addr.takeError());
372     return 0;
373   }
374 
375   return Addr->toPtr<void *>();
376 }
377 
378 int MachOPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
379                                               void *DSOHandle) {
380   // FIXME: Handle out-of-memory errors, returning -1 if OOM.
381   std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
382   auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);
383   assert(JDS && "JITDylib state not initialized");
384   JDS->AtExits.push_back({F, Arg});
385   return 0;
386 }
387 
388 void MachOPlatformRuntimeState::runAtExits(void *DSOHandle) {
389   // FIXME: Should atexits be allowed to run concurrently with access to
390   // JDState?
391   AtExitsVector V;
392   {
393     std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
394     auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);
395     assert(JDS && "JITDlybi state not initialized");
396     std::swap(V, JDS->AtExits);
397   }
398 
399   while (!V.empty()) {
400     auto &AE = V.back();
401     AE.Func(AE.Arg);
402     V.pop_back();
403   }
404 }
405 
406 Expected<std::pair<const char *, size_t>>
407 MachOPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {
408   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
409   auto I = ThreadDataSections.upper_bound(ThreadData);
410   // Check that we have a valid entry covering this address.
411   if (I == ThreadDataSections.begin())
412     return make_error<StringError>("No thread local data section for key");
413   I = std::prev(I);
414   if (ThreadData >= I->first + I->second)
415     return make_error<StringError>("No thread local data section for key");
416   return *I;
417 }
418 
419 MachOPlatformRuntimeState::PerJITDylibState *
420 MachOPlatformRuntimeState::getJITDylibStateByHeaderAddr(void *DSOHandle) {
421   auto I = JDStates.find(DSOHandle);
422   if (I == JDStates.end())
423     return nullptr;
424   return &I->second;
425 }
426 
427 MachOPlatformRuntimeState::PerJITDylibState *
428 MachOPlatformRuntimeState::getJITDylibStateByName(string_view Name) {
429   // FIXME: Avoid creating string copy here.
430   auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
431   if (I == JDNameToHeader.end())
432     return nullptr;
433   void *H = I->second;
434   auto J = JDStates.find(H);
435   assert(J != JDStates.end() &&
436          "JITDylib has name map entry but no header map entry");
437   return &J->second;
438 }
439 
440 MachOPlatformRuntimeState::PerJITDylibState &
441 MachOPlatformRuntimeState::getOrCreateJITDylibState(
442     MachOJITDylibInitializers &MOJDIs) {
443   void *Header = MOJDIs.MachOHeaderAddress.toPtr<void *>();
444 
445   auto &JDS = JDStates[Header];
446 
447   // If this entry hasn't been created yet.
448   if (!JDS.Header) {
449     assert(!JDNameToHeader.count(MOJDIs.Name) &&
450            "JITDylib has header map entry but no name map entry");
451     JDNameToHeader[MOJDIs.Name] = Header;
452     JDS.Header = Header;
453   }
454 
455   return JDS;
456 }
457 
458 Expected<ExecutorAddr>
459 MachOPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,
460                                                   string_view Sym) {
461   Expected<ExecutorAddr> Result((ExecutorAddr()));
462   if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>(
463           SPSExecutorAddr, SPSString)>::call(&__orc_rt_macho_symbol_lookup_tag,
464                                              Result,
465                                              ExecutorAddr::fromPtr(DSOHandle),
466                                              Sym))
467     return std::move(Err);
468   return Result;
469 }
470 
471 Expected<MachOJITDylibInitializerSequence>
472 MachOPlatformRuntimeState::getJITDylibInitializersByName(string_view Path) {
473   Expected<MachOJITDylibInitializerSequence> Result(
474       (MachOJITDylibInitializerSequence()));
475   std::string PathStr(Path.data(), Path.size());
476   if (auto Err =
477           WrapperFunction<SPSExpected<SPSMachOJITDylibInitializerSequence>(
478               SPSString)>::call(&__orc_rt_macho_get_initializers_tag, Result,
479                                 Path))
480     return std::move(Err);
481   return Result;
482 }
483 
484 Expected<void *> MachOPlatformRuntimeState::dlopenInitialize(string_view Path,
485                                                              int Mode) {
486   // Either our JITDylib wasn't loaded, or it or one of its dependencies allows
487   // reinitialization. We need to call in to the JIT to see if there's any new
488   // work pending.
489   auto InitSeq = getJITDylibInitializersByName(Path);
490   if (!InitSeq)
491     return InitSeq.takeError();
492 
493   // Init sequences should be non-empty.
494   if (InitSeq->empty())
495     return make_error<StringError>(
496         "__orc_rt_macho_get_initializers returned an "
497         "empty init sequence");
498 
499   // Otherwise register and run initializers for each JITDylib.
500   for (auto &MOJDIs : *InitSeq)
501     if (auto Err = initializeJITDylib(MOJDIs))
502       return std::move(Err);
503 
504   // Return the header for the last item in the list.
505   auto *JDS = getJITDylibStateByHeaderAddr(
506       InitSeq->back().MachOHeaderAddress.toPtr<void *>());
507   assert(JDS && "Missing state entry for JD");
508   return JDS->Header;
509 }
510 
511 Error MachOPlatformRuntimeState::initializeJITDylib(
512     MachOJITDylibInitializers &MOJDIs) {
513 
514   auto &JDS = getOrCreateJITDylibState(MOJDIs);
515   ++JDS.RefCount;
516 
517   for (auto &KV : InitSections) {
518     const auto &Name = KV.first;
519     const auto &Handler = KV.second;
520     auto I = MOJDIs.InitSections.find(Name);
521     if (I != MOJDIs.InitSections.end()) {
522       if (auto Err = Handler(I->second, MOJDIs))
523         return Err;
524     }
525   }
526 
527   return Error::success();
528 }
529 
530 class MachOPlatformRuntimeTLVManager {
531 public:
532   void *getInstance(const char *ThreadData);
533 
534 private:
535   std::unordered_map<const char *, char *> Instances;
536   std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;
537 };
538 
539 void *MachOPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {
540   auto I = Instances.find(ThreadData);
541   if (I != Instances.end())
542     return I->second;
543 
544   auto TDS =
545       MachOPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);
546   if (!TDS) {
547     __orc_rt_log_error(toString(TDS.takeError()).c_str());
548     return nullptr;
549   }
550 
551   auto &Allocated = AllocatedSections[TDS->first];
552   if (!Allocated) {
553     Allocated = std::make_unique<char[]>(TDS->second);
554     memcpy(Allocated.get(), TDS->first, TDS->second);
555   }
556 
557   size_t ThreadDataDelta = ThreadData - TDS->first;
558   assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");
559 
560   char *Instance = Allocated.get() + ThreadDataDelta;
561   Instances[ThreadData] = Instance;
562   return Instance;
563 }
564 
565 void destroyMachOTLVMgr(void *MachOTLVMgr) {
566   delete static_cast<MachOPlatformRuntimeTLVManager *>(MachOTLVMgr);
567 }
568 
569 Error runWrapperFunctionCalls(std::vector<WrapperFunctionCall> WFCs) {
570   for (auto &WFC : WFCs)
571     if (auto Err = WFC.runWithSPSRet<void>())
572       return Err;
573   return Error::success();
574 }
575 
576 } // end anonymous namespace
577 
578 //------------------------------------------------------------------------------
579 //                             JIT entry points
580 //------------------------------------------------------------------------------
581 
582 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
583 __orc_rt_macho_platform_bootstrap(char *ArgData, size_t ArgSize) {
584   MachOPlatformRuntimeState::initialize();
585   return WrapperFunctionResult().release();
586 }
587 
588 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
589 __orc_rt_macho_platform_shutdown(char *ArgData, size_t ArgSize) {
590   MachOPlatformRuntimeState::destroy();
591   return WrapperFunctionResult().release();
592 }
593 
594 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
595 __orc_rt_macho_register_thread_data_section(char *ArgData, size_t ArgSize) {
596   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
597              ArgData, ArgSize,
598              [](ExecutorAddrRange R) {
599                return MachOPlatformRuntimeState::get()
600                    .registerThreadDataSection(R.toSpan<const char>());
601              })
602       .release();
603 }
604 
605 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
606 __orc_rt_macho_deregister_thread_data_section(char *ArgData, size_t ArgSize) {
607   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
608              ArgData, ArgSize,
609              [](ExecutorAddrRange R) {
610                return MachOPlatformRuntimeState::get()
611                    .deregisterThreadDataSection(R.toSpan<const char>());
612              })
613       .release();
614 }
615 
616 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
617 __orc_rt_macho_run_wrapper_function_calls(char *ArgData, size_t ArgSize) {
618   return WrapperFunction<SPSError(SPSSequence<SPSWrapperFunctionCall>)>::handle(
619              ArgData, ArgSize, runWrapperFunctionCalls)
620       .release();
621 }
622 
623 //------------------------------------------------------------------------------
624 //                            TLV support
625 //------------------------------------------------------------------------------
626 
627 ORC_RT_INTERFACE void *__orc_rt_macho_tlv_get_addr_impl(TLVDescriptor *D) {
628   auto *TLVMgr = static_cast<MachOPlatformRuntimeTLVManager *>(
629       pthread_getspecific(D->Key));
630   if (!TLVMgr) {
631     TLVMgr = new MachOPlatformRuntimeTLVManager();
632     if (pthread_setspecific(D->Key, TLVMgr)) {
633       __orc_rt_log_error("Call to pthread_setspecific failed");
634       return nullptr;
635     }
636   }
637 
638   return TLVMgr->getInstance(
639       reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));
640 }
641 
642 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
643 __orc_rt_macho_create_pthread_key(char *ArgData, size_t ArgSize) {
644   return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(
645              ArgData, ArgSize,
646              []() -> Expected<uint64_t> {
647                pthread_key_t Key;
648                if (int Err = pthread_key_create(&Key, destroyMachOTLVMgr)) {
649                  __orc_rt_log_error("Call to pthread_key_create failed");
650                  return make_error<StringError>(strerror(Err));
651                }
652                return static_cast<uint64_t>(Key);
653              })
654       .release();
655 }
656 
657 //------------------------------------------------------------------------------
658 //                           cxa_atexit support
659 //------------------------------------------------------------------------------
660 
661 int __orc_rt_macho_cxa_atexit(void (*func)(void *), void *arg,
662                               void *dso_handle) {
663   return MachOPlatformRuntimeState::get().registerAtExit(func, arg, dso_handle);
664 }
665 
666 void __orc_rt_macho_cxa_finalize(void *dso_handle) {
667   MachOPlatformRuntimeState::get().runAtExits(dso_handle);
668 }
669 
670 //------------------------------------------------------------------------------
671 //                        JIT'd dlfcn alternatives.
672 //------------------------------------------------------------------------------
673 
674 const char *__orc_rt_macho_jit_dlerror() {
675   return MachOPlatformRuntimeState::get().dlerror();
676 }
677 
678 void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
679   return MachOPlatformRuntimeState::get().dlopen(path, mode);
680 }
681 
682 int __orc_rt_macho_jit_dlclose(void *dso_handle) {
683   return MachOPlatformRuntimeState::get().dlclose(dso_handle);
684 }
685 
686 void *__orc_rt_macho_jit_dlsym(void *dso_handle, const char *symbol) {
687   return MachOPlatformRuntimeState::get().dlsym(dso_handle, symbol);
688 }
689 
690 //------------------------------------------------------------------------------
691 //                             MachO Run Program
692 //------------------------------------------------------------------------------
693 
694 ORC_RT_INTERFACE int64_t __orc_rt_macho_run_program(const char *JITDylibName,
695                                                     const char *EntrySymbolName,
696                                                     int argc, char *argv[]) {
697   using MainTy = int (*)(int, char *[]);
698 
699   void *H = __orc_rt_macho_jit_dlopen(JITDylibName,
700                                       __orc_rt::macho::ORC_RT_RTLD_LAZY);
701   if (!H) {
702     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
703     return -1;
704   }
705 
706   auto *Main =
707       reinterpret_cast<MainTy>(__orc_rt_macho_jit_dlsym(H, EntrySymbolName));
708 
709   if (!Main) {
710     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
711     return -1;
712   }
713 
714   int Result = Main(argc, argv);
715 
716   if (__orc_rt_macho_jit_dlclose(H) == -1)
717     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
718 
719   return Result;
720 }
721