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