xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/EHFrameSupport.h"
13 #include "llvm/ExecutionEngine/JITLink/MachO.h"
14 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
15 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
16 #include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
17 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
18 #include "llvm/ExecutionEngine/Orc/MachOBuilder.h"
19 #include "llvm/Support/Debug.h"
20 #include <optional>
21 
22 #define DEBUG_TYPE "orc"
23 
24 using namespace llvm;
25 using namespace llvm::orc;
26 using namespace llvm::orc::shared;
27 
28 namespace llvm {
29 namespace orc {
30 namespace shared {
31 
32 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
33 using SPSMachOJITDylibDepInfoMap =
34     SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
35 
36 class SPSMachOExecutorSymbolFlags;
37 
38 template <>
39 class SPSSerializationTraits<SPSMachOJITDylibDepInfo,
40                              MachOPlatform::MachOJITDylibDepInfo> {
41 public:
size(const MachOPlatform::MachOJITDylibDepInfo & DDI)42   static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) {
43     return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders);
44   }
45 
serialize(SPSOutputBuffer & OB,const MachOPlatform::MachOJITDylibDepInfo & DDI)46   static bool serialize(SPSOutputBuffer &OB,
47                         const MachOPlatform::MachOJITDylibDepInfo &DDI) {
48     return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed,
49                                                          DDI.DepHeaders);
50   }
51 
deserialize(SPSInputBuffer & IB,MachOPlatform::MachOJITDylibDepInfo & DDI)52   static bool deserialize(SPSInputBuffer &IB,
53                           MachOPlatform::MachOJITDylibDepInfo &DDI) {
54     return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed,
55                                                            DDI.DepHeaders);
56   }
57 };
58 
59 template <>
60 class SPSSerializationTraits<SPSMachOExecutorSymbolFlags,
61                              MachOPlatform::MachOExecutorSymbolFlags> {
62 private:
63   using UT = std::underlying_type_t<MachOPlatform::MachOExecutorSymbolFlags>;
64 
65 public:
size(const MachOPlatform::MachOExecutorSymbolFlags & SF)66   static size_t size(const MachOPlatform::MachOExecutorSymbolFlags &SF) {
67     return sizeof(UT);
68   }
69 
serialize(SPSOutputBuffer & OB,const MachOPlatform::MachOExecutorSymbolFlags & SF)70   static bool serialize(SPSOutputBuffer &OB,
71                         const MachOPlatform::MachOExecutorSymbolFlags &SF) {
72     return SPSArgList<UT>::serialize(OB, static_cast<UT>(SF));
73   }
74 
deserialize(SPSInputBuffer & IB,MachOPlatform::MachOExecutorSymbolFlags & SF)75   static bool deserialize(SPSInputBuffer &IB,
76                           MachOPlatform::MachOExecutorSymbolFlags &SF) {
77     UT Tmp;
78     if (!SPSArgList<UT>::deserialize(IB, Tmp))
79       return false;
80     SF = static_cast<MachOPlatform::MachOExecutorSymbolFlags>(Tmp);
81     return true;
82   }
83 };
84 
85 } // namespace shared
86 } // namespace orc
87 } // namespace llvm
88 
89 namespace {
90 
91 using SPSRegisterSymbolsArgs =
92     SPSArgList<SPSExecutorAddr,
93                SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
94                                     SPSMachOExecutorSymbolFlags>>>;
95 
createPlatformGraph(MachOPlatform & MOP,std::string Name)96 std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
97                                                         std::string Name) {
98   auto &ES = MOP.getExecutionSession();
99   return std::make_unique<jitlink::LinkGraph>(
100       std::move(Name), ES.getSymbolStringPool(), ES.getTargetTriple(),
101       SubtargetFeatures(), jitlink::getGenericEdgeKindName);
102 }
103 
104 // Creates a Bootstrap-Complete LinkGraph to run deferred actions.
105 class MachOPlatformCompleteBootstrapMaterializationUnit
106     : public MaterializationUnit {
107 public:
108   using SymbolTableVector =
109       SmallVector<std::tuple<ExecutorAddr, ExecutorAddr,
110                              MachOPlatform::MachOExecutorSymbolFlags>>;
111 
MachOPlatformCompleteBootstrapMaterializationUnit(MachOPlatform & MOP,StringRef PlatformJDName,SymbolStringPtr CompleteBootstrapSymbol,SymbolTableVector SymTab,shared::AllocActions DeferredAAs,ExecutorAddr MachOHeaderAddr,ExecutorAddr PlatformBootstrap,ExecutorAddr PlatformShutdown,ExecutorAddr RegisterJITDylib,ExecutorAddr DeregisterJITDylib,ExecutorAddr RegisterObjectSymbolTable,ExecutorAddr DeregisterObjectSymbolTable)112   MachOPlatformCompleteBootstrapMaterializationUnit(
113       MachOPlatform &MOP, StringRef PlatformJDName,
114       SymbolStringPtr CompleteBootstrapSymbol, SymbolTableVector SymTab,
115       shared::AllocActions DeferredAAs, ExecutorAddr MachOHeaderAddr,
116       ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,
117       ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,
118       ExecutorAddr RegisterObjectSymbolTable,
119       ExecutorAddr DeregisterObjectSymbolTable)
120       : MaterializationUnit(
121             {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
122         MOP(MOP), PlatformJDName(PlatformJDName),
123         CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
124         SymTab(std::move(SymTab)), DeferredAAs(std::move(DeferredAAs)),
125         MachOHeaderAddr(MachOHeaderAddr), PlatformBootstrap(PlatformBootstrap),
126         PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
127         DeregisterJITDylib(DeregisterJITDylib),
128         RegisterObjectSymbolTable(RegisterObjectSymbolTable),
129         DeregisterObjectSymbolTable(DeregisterObjectSymbolTable) {}
130 
getName() const131   StringRef getName() const override {
132     return "MachOPlatformCompleteBootstrap";
133   }
134 
materialize(std::unique_ptr<MaterializationResponsibility> R)135   void materialize(std::unique_ptr<MaterializationResponsibility> R) override {
136     using namespace jitlink;
137     auto G = createPlatformGraph(MOP, "<OrcRTCompleteBootstrap>");
138     auto &PlaceholderSection =
139         G->createSection("__orc_rt_cplt_bs", MemProt::Read);
140     auto &PlaceholderBlock =
141         G->createZeroFillBlock(PlaceholderSection, 1, ExecutorAddr(), 1, 0);
142     G->addDefinedSymbol(PlaceholderBlock, 0, *CompleteBootstrapSymbol, 1,
143                         Linkage::Strong, Scope::Hidden, false, true);
144 
145     // Reserve space for the stolen actions, plus two extras.
146     G->allocActions().reserve(DeferredAAs.size() + 3);
147 
148     // 1. Bootstrap the platform support code.
149     G->allocActions().push_back(
150         {cantFail(WrapperFunctionCall::Create<SPSArgList<>>(PlatformBootstrap)),
151          cantFail(
152              WrapperFunctionCall::Create<SPSArgList<>>(PlatformShutdown))});
153 
154     // 2. Register the platform JITDylib.
155     G->allocActions().push_back(
156         {cantFail(WrapperFunctionCall::Create<
157                   SPSArgList<SPSString, SPSExecutorAddr>>(
158              RegisterJITDylib, PlatformJDName, MachOHeaderAddr)),
159          cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
160              DeregisterJITDylib, MachOHeaderAddr))});
161 
162     // 3. Register deferred symbols.
163     G->allocActions().push_back(
164         {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
165              RegisterObjectSymbolTable, MachOHeaderAddr, SymTab)),
166          cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
167              DeregisterObjectSymbolTable, MachOHeaderAddr, SymTab))});
168 
169     // 4. Add the deferred actions to the graph.
170     std::move(DeferredAAs.begin(), DeferredAAs.end(),
171               std::back_inserter(G->allocActions()));
172 
173     MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
174   }
175 
discard(const JITDylib & JD,const SymbolStringPtr & Sym)176   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {}
177 
178 private:
179   MachOPlatform &MOP;
180   StringRef PlatformJDName;
181   SymbolStringPtr CompleteBootstrapSymbol;
182   SymbolTableVector SymTab;
183   shared::AllocActions DeferredAAs;
184   ExecutorAddr MachOHeaderAddr;
185   ExecutorAddr PlatformBootstrap;
186   ExecutorAddr PlatformShutdown;
187   ExecutorAddr RegisterJITDylib;
188   ExecutorAddr DeregisterJITDylib;
189   ExecutorAddr RegisterObjectSymbolTable;
190   ExecutorAddr DeregisterObjectSymbolTable;
191 };
192 
193 static StringRef ObjCRuntimeObjectSectionsData[] = {
194     MachOObjCCatListSectionName,   MachOObjCCatList2SectionName,
195     MachOObjCClassListSectionName, MachOObjCClassRefsSectionName,
196     MachOObjCConstSectionName,     MachOObjCDataSectionName,
197     MachOObjCProtoListSectionName, MachOObjCProtoRefsSectionName,
198     MachOObjCNLCatListSectionName, MachOObjCNLClassListSectionName,
199     MachOObjCSelRefsSectionName};
200 
201 static StringRef ObjCRuntimeObjectSectionsText[] = {
202     MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,
203     MachOObjCMethTypeSectionName,  MachOSwift5TypesSectionName,
204     MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
205     MachOSwift5EntrySectionName,   MachOSwift5ProtoSectionName,
206     MachOSwift5ProtosSectionName};
207 
208 static StringRef ObjCRuntimeObjectSectionName =
209     "__llvm_jitlink_ObjCRuntimeRegistrationObject";
210 
211 static StringRef ObjCImageInfoSymbolName =
212     "__llvm_jitlink_macho_objc_imageinfo";
213 
214 struct ObjCImageInfoFlags {
215   uint16_t SwiftABIVersion;
216   uint16_t SwiftVersion;
217   bool HasCategoryClassProperties;
218   bool HasSignedObjCClassROs;
219 
220   static constexpr uint32_t SIGNED_CLASS_RO = (1 << 4);
221   static constexpr uint32_t HAS_CATEGORY_CLASS_PROPERTIES = (1 << 6);
222 
ObjCImageInfoFlags__anon04a50ca90111::ObjCImageInfoFlags223   explicit ObjCImageInfoFlags(uint32_t RawFlags) {
224     HasSignedObjCClassROs = RawFlags & SIGNED_CLASS_RO;
225     HasCategoryClassProperties = RawFlags & HAS_CATEGORY_CLASS_PROPERTIES;
226     SwiftABIVersion = (RawFlags >> 8) & 0xFF;
227     SwiftVersion = (RawFlags >> 16) & 0xFFFF;
228   }
229 
rawFlags__anon04a50ca90111::ObjCImageInfoFlags230   uint32_t rawFlags() const {
231     uint32_t Result = 0;
232     if (HasCategoryClassProperties)
233       Result |= HAS_CATEGORY_CLASS_PROPERTIES;
234     if (HasSignedObjCClassROs)
235       Result |= SIGNED_CLASS_RO;
236     Result |= (SwiftABIVersion << 8);
237     Result |= (SwiftVersion << 16);
238     return Result;
239   }
240 };
241 } // end anonymous namespace
242 
243 namespace llvm {
244 namespace orc {
245 
246 std::optional<MachOPlatform::HeaderOptions::BuildVersionOpts>
fromTriple(const Triple & TT,uint32_t MinOS,uint32_t SDK)247 MachOPlatform::HeaderOptions::BuildVersionOpts::fromTriple(const Triple &TT,
248                                                            uint32_t MinOS,
249                                                            uint32_t SDK) {
250 
251   uint32_t Platform;
252   switch (TT.getOS()) {
253   case Triple::IOS:
254     Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_IOSSIMULATOR
255                                            : MachO::PLATFORM_IOS;
256     break;
257   case Triple::MacOSX:
258     Platform = MachO::PLATFORM_MACOS;
259     break;
260   case Triple::TvOS:
261     Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_TVOSSIMULATOR
262                                            : MachO::PLATFORM_TVOS;
263     break;
264   case Triple::WatchOS:
265     Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_WATCHOSSIMULATOR
266                                            : MachO::PLATFORM_WATCHOS;
267     break;
268   case Triple::XROS:
269     Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_XROS_SIMULATOR
270                                            : MachO::PLATFORM_XROS;
271     break;
272   default:
273     return std::nullopt;
274   }
275 
276   return MachOPlatform::HeaderOptions::BuildVersionOpts{Platform, MinOS, SDK};
277 }
278 
279 Expected<std::unique_ptr<MachOPlatform>>
Create(ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,std::unique_ptr<DefinitionGenerator> OrcRuntime,HeaderOptions PlatformJDOpts,MachOHeaderMUBuilder BuildMachOHeaderMU,std::optional<SymbolAliasMap> RuntimeAliases)280 MachOPlatform::Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
281                       std::unique_ptr<DefinitionGenerator> OrcRuntime,
282                       HeaderOptions PlatformJDOpts,
283                       MachOHeaderMUBuilder BuildMachOHeaderMU,
284                       std::optional<SymbolAliasMap> RuntimeAliases) {
285 
286   auto &ES = ObjLinkingLayer.getExecutionSession();
287 
288   // If the target is not supported then bail out immediately.
289   if (!supportedTarget(ES.getTargetTriple()))
290     return make_error<StringError>("Unsupported MachOPlatform triple: " +
291                                        ES.getTargetTriple().str(),
292                                    inconvertibleErrorCode());
293 
294   auto &EPC = ES.getExecutorProcessControl();
295 
296   // Create default aliases if the caller didn't supply any.
297   if (!RuntimeAliases)
298     RuntimeAliases = standardPlatformAliases(ES);
299 
300   // Define the aliases.
301   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
302     return std::move(Err);
303 
304   // Add JIT-dispatch function support symbols.
305   if (auto Err = PlatformJD.define(
306           absoluteSymbols({{ES.intern("___orc_rt_jit_dispatch"),
307                             {EPC.getJITDispatchInfo().JITDispatchFunction,
308                              JITSymbolFlags::Exported}},
309                            {ES.intern("___orc_rt_jit_dispatch_ctx"),
310                             {EPC.getJITDispatchInfo().JITDispatchContext,
311                              JITSymbolFlags::Exported}}})))
312     return std::move(Err);
313 
314   // Create the instance.
315   Error Err = Error::success();
316   auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform(
317       ObjLinkingLayer, PlatformJD, std::move(OrcRuntime),
318       std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU), Err));
319   if (Err)
320     return std::move(Err);
321   return std::move(P);
322 }
323 
324 Expected<std::unique_ptr<MachOPlatform>>
Create(ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,const char * OrcRuntimePath,HeaderOptions PlatformJDOpts,MachOHeaderMUBuilder BuildMachOHeaderMU,std::optional<SymbolAliasMap> RuntimeAliases)325 MachOPlatform::Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
326                       const char *OrcRuntimePath, HeaderOptions PlatformJDOpts,
327                       MachOHeaderMUBuilder BuildMachOHeaderMU,
328                       std::optional<SymbolAliasMap> RuntimeAliases) {
329 
330   // Create a generator for the ORC runtime archive.
331   auto OrcRuntimeArchiveGenerator =
332       StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
333   if (!OrcRuntimeArchiveGenerator)
334     return OrcRuntimeArchiveGenerator.takeError();
335 
336   return Create(ObjLinkingLayer, PlatformJD,
337                 std::move(*OrcRuntimeArchiveGenerator),
338                 std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU),
339                 std::move(RuntimeAliases));
340 }
341 
setupJITDylib(JITDylib & JD)342 Error MachOPlatform::setupJITDylib(JITDylib &JD) {
343   return setupJITDylib(JD, /*Opts=*/{});
344 }
345 
setupJITDylib(JITDylib & JD,HeaderOptions Opts)346 Error MachOPlatform::setupJITDylib(JITDylib &JD, HeaderOptions Opts) {
347   if (auto Err = JD.define(BuildMachOHeaderMU(*this, std::move(Opts))))
348     return Err;
349 
350   return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError();
351 }
352 
teardownJITDylib(JITDylib & JD)353 Error MachOPlatform::teardownJITDylib(JITDylib &JD) {
354   std::lock_guard<std::mutex> Lock(PlatformMutex);
355   auto I = JITDylibToHeaderAddr.find(&JD);
356   if (I != JITDylibToHeaderAddr.end()) {
357     assert(HeaderAddrToJITDylib.count(I->second) &&
358            "HeaderAddrToJITDylib missing entry");
359     HeaderAddrToJITDylib.erase(I->second);
360     JITDylibToHeaderAddr.erase(I);
361   }
362   JITDylibToPThreadKey.erase(&JD);
363   return Error::success();
364 }
365 
notifyAdding(ResourceTracker & RT,const MaterializationUnit & MU)366 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
367                                   const MaterializationUnit &MU) {
368   auto &JD = RT.getJITDylib();
369   const auto &InitSym = MU.getInitializerSymbol();
370   if (!InitSym)
371     return Error::success();
372 
373   RegisteredInitSymbols[&JD].add(InitSym,
374                                  SymbolLookupFlags::WeaklyReferencedSymbol);
375   LLVM_DEBUG({
376     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
377            << MU.getName() << "\n";
378   });
379   return Error::success();
380 }
381 
notifyRemoving(ResourceTracker & RT)382 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
383   llvm_unreachable("Not supported yet");
384 }
385 
addAliases(ExecutionSession & ES,SymbolAliasMap & Aliases,ArrayRef<std::pair<const char *,const char * >> AL)386 static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
387                        ArrayRef<std::pair<const char *, const char *>> AL) {
388   for (auto &KV : AL) {
389     auto AliasName = ES.intern(KV.first);
390     assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map");
391     Aliases[std::move(AliasName)] = {ES.intern(KV.second),
392                                      JITSymbolFlags::Exported};
393   }
394 }
395 
standardPlatformAliases(ExecutionSession & ES)396 SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) {
397   SymbolAliasMap Aliases;
398   addAliases(ES, Aliases, requiredCXXAliases());
399   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
400   addAliases(ES, Aliases, standardLazyCompilationAliases());
401   return Aliases;
402 }
403 
404 ArrayRef<std::pair<const char *, const char *>>
requiredCXXAliases()405 MachOPlatform::requiredCXXAliases() {
406   static const std::pair<const char *, const char *> RequiredCXXAliases[] = {
407       {"___cxa_atexit", "___orc_rt_macho_cxa_atexit"}};
408 
409   return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases);
410 }
411 
412 ArrayRef<std::pair<const char *, const char *>>
standardRuntimeUtilityAliases()413 MachOPlatform::standardRuntimeUtilityAliases() {
414   static const std::pair<const char *, const char *>
415       StandardRuntimeUtilityAliases[] = {
416           {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
417           {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
418           {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
419           {"___orc_rt_jit_dlupdate", "___orc_rt_macho_jit_dlupdate"},
420           {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
421           {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
422           {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
423 
424   return ArrayRef<std::pair<const char *, const char *>>(
425       StandardRuntimeUtilityAliases);
426 }
427 
428 ArrayRef<std::pair<const char *, const char *>>
standardLazyCompilationAliases()429 MachOPlatform::standardLazyCompilationAliases() {
430   static const std::pair<const char *, const char *>
431       StandardLazyCompilationAliases[] = {
432           {"__orc_rt_reenter", "__orc_rt_sysv_reenter"},
433           {"__orc_rt_resolve_tag", "___orc_rt_resolve_tag"}};
434 
435   return ArrayRef<std::pair<const char *, const char *>>(
436       StandardLazyCompilationAliases);
437 }
438 
supportedTarget(const Triple & TT)439 bool MachOPlatform::supportedTarget(const Triple &TT) {
440   switch (TT.getArch()) {
441   case Triple::aarch64:
442   case Triple::x86_64:
443     return true;
444   default:
445     return false;
446   }
447 }
448 
getPointerEdgeKind(jitlink::LinkGraph & G)449 jitlink::Edge::Kind MachOPlatform::getPointerEdgeKind(jitlink::LinkGraph &G) {
450   switch (G.getTargetTriple().getArch()) {
451   case Triple::aarch64:
452     return jitlink::aarch64::Pointer64;
453   case Triple::x86_64:
454     return jitlink::x86_64::Pointer64;
455   default:
456     llvm_unreachable("Unsupported architecture");
457   }
458 }
459 
460 MachOPlatform::MachOExecutorSymbolFlags
flagsForSymbol(jitlink::Symbol & Sym)461 MachOPlatform::flagsForSymbol(jitlink::Symbol &Sym) {
462   MachOPlatform::MachOExecutorSymbolFlags Flags{};
463   if (Sym.getLinkage() == jitlink::Linkage::Weak)
464     Flags |= MachOExecutorSymbolFlags::Weak;
465 
466   if (Sym.isCallable())
467     Flags |= MachOExecutorSymbolFlags::Callable;
468 
469   return Flags;
470 }
471 
MachOPlatform(ObjectLinkingLayer & ObjLinkingLayer,JITDylib & PlatformJD,std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,HeaderOptions PlatformJDOpts,MachOHeaderMUBuilder BuildMachOHeaderMU,Error & Err)472 MachOPlatform::MachOPlatform(
473     ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
474     std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
475     HeaderOptions PlatformJDOpts, MachOHeaderMUBuilder BuildMachOHeaderMU,
476     Error &Err)
477     : ES(ObjLinkingLayer.getExecutionSession()), PlatformJD(PlatformJD),
478       ObjLinkingLayer(ObjLinkingLayer),
479       BuildMachOHeaderMU(std::move(BuildMachOHeaderMU)) {
480   ErrorAsOutParameter _(Err);
481   ObjLinkingLayer.addPlugin(std::make_unique<MachOPlatformPlugin>(*this));
482   PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
483 
484   {
485     // Check for force-eh-frame
486     std::optional<bool> ForceEHFrames;
487     if ((Err = ES.getBootstrapMapValue<bool, bool>("darwin-use-ehframes-only",
488                                                    ForceEHFrames)))
489       return;
490     this->ForceEHFrames = ForceEHFrames.value_or(false);
491   }
492 
493   BootstrapInfo BI;
494   Bootstrap = &BI;
495 
496   // Bootstrap process -- here be phase-ordering dragons.
497   //
498   // The MachOPlatform class uses allocation actions to register metadata
499   // sections with the ORC runtime, however the runtime contains metadata
500   // registration functions that have their own metadata that they need to
501   // register (e.g. the frame-info registration functions have frame-info).
502   // We can't use an ordinary lookup to find these registration functions
503   // because their address is needed during the link of the containing graph
504   // itself (to build the allocation actions that will call the registration
505   // functions). Further complicating the situation (a) the graph containing
506   // the registration functions is allowed to depend on other graphs (e.g. the
507   // graph containing the ORC runtime RTTI support) so we need to handle an
508   // unknown set of dependencies during bootstrap, and (b) these graphs may
509   // be linked concurrently if the user has installed a concurrent dispatcher.
510   //
511   // We satisfy these constraints by implementing a bootstrap phase during which
512   // allocation actions generated by MachOPlatform are appended to a list of
513   // deferred allocation actions, rather than to the graphs themselves. At the
514   // end of the bootstrap process the deferred actions are attached to a final
515   // "complete-bootstrap" graph that causes them to be run.
516   //
517   // The bootstrap steps are as follows:
518   //
519   // 1. Request the graph containing the mach header. This graph is guaranteed
520   //    not to have any metadata so the fact that the registration functions
521   //    are not available yet is not a problem.
522   //
523   // 2. Look up the registration functions and discard the results. This will
524   //    trigger linking of the graph containing these functions, and
525   //    consequently any graphs that it depends on. We do not use the lookup
526   //    result to find the addresses of the functions requested (as described
527   //    above the lookup will return too late for that), instead we capture the
528   //    addresses in a post-allocation pass injected by the platform runtime
529   //    during bootstrap only.
530   //
531   // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of
532   //    graphs being linked (potentially concurrently), and we block until all
533   //    of these graphs have completed linking. This is to avoid a race on the
534   //    deferred-actions vector: the lookup for the runtime registration
535   //    functions may return while some functions (those that are being
536   //    incidentally linked in, but aren't reachable via the runtime functions)
537   //    are still being linked, and we need to capture any allocation actions
538   //    for this incidental code before we proceed.
539   //
540   // 4. Once all active links are complete we transfer the deferred actions to
541   //    a newly added CompleteBootstrap graph and then request a symbol from
542   //    the CompleteBootstrap graph to trigger materialization. This will cause
543   //    all deferred actions to be run, and once this lookup returns we can
544   //    proceed.
545   //
546   // 5. Finally, we associate runtime support methods in MachOPlatform with
547   //    the corresponding jit-dispatch tag variables in the ORC runtime to make
548   //    the support methods callable. The bootstrap is now complete.
549 
550   // Step (1) Add header materialization unit and request.
551   if ((Err = PlatformJD.define(
552            this->BuildMachOHeaderMU(*this, std::move(PlatformJDOpts)))))
553     return;
554   if ((Err = ES.lookup(&PlatformJD, MachOHeaderStartSymbol).takeError()))
555     return;
556 
557   // Step (2) Request runtime registration functions to trigger
558   // materialization..
559   if ((Err = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
560                        SymbolLookupSet(
561                            {PlatformBootstrap.Name, PlatformShutdown.Name,
562                             RegisterJITDylib.Name, DeregisterJITDylib.Name,
563                             RegisterObjectSymbolTable.Name,
564                             DeregisterObjectSymbolTable.Name,
565                             RegisterObjectPlatformSections.Name,
566                             DeregisterObjectPlatformSections.Name,
567                             CreatePThreadKey.Name}))
568                  .takeError()))
569     return;
570 
571   // Step (3) Wait for any incidental linker work to complete.
572   {
573     std::unique_lock<std::mutex> Lock(PlatformMutex);
574     BI.CV.wait(Lock, [&]() { return BI.ActiveGraphs == 0; });
575     Bootstrap = nullptr;
576   }
577 
578   // Step (4) Add complete-bootstrap materialization unit and request.
579   auto BootstrapCompleteSymbol = ES.intern("__orc_rt_macho_complete_bootstrap");
580   if ((Err = PlatformJD.define(
581            std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(
582                *this, PlatformJD.getName(), BootstrapCompleteSymbol,
583                std::move(BI.SymTab), std::move(BI.DeferredAAs),
584                BI.MachOHeaderAddr, PlatformBootstrap.Addr,
585                PlatformShutdown.Addr, RegisterJITDylib.Addr,
586                DeregisterJITDylib.Addr, RegisterObjectSymbolTable.Addr,
587                DeregisterObjectSymbolTable.Addr))))
588     return;
589   if ((Err = ES.lookup(makeJITDylibSearchOrder(
590                            &PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
591                        std::move(BootstrapCompleteSymbol))
592                  .takeError()))
593     return;
594 
595   // (5) Associate runtime support functions.
596   // TODO: Consider moving this above (4) to make runtime support functions
597   //       available to the bootstrap completion graph. We'd just need to be
598   //       sure that the runtime support functions are fully usable before any
599   //       bootstrap completion actions use them (e.g. the ORC runtime
600   //       macho_platform object would have to have been created and
601   //       initialized).
602   if ((Err = associateRuntimeSupportFunctions()))
603     return;
604 }
605 
associateRuntimeSupportFunctions()606 Error MachOPlatform::associateRuntimeSupportFunctions() {
607   ExecutionSession::JITDispatchHandlerAssociationMap WFs;
608 
609   using PushInitializersSPSSig =
610       SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr);
611   WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] =
612       ES.wrapAsyncWithSPS<PushInitializersSPSSig>(
613           this, &MachOPlatform::rt_pushInitializers);
614 
615   using PushSymbolsSPSSig =
616       SPSError(SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>);
617   WFs[ES.intern("___orc_rt_macho_push_symbols_tag")] =
618       ES.wrapAsyncWithSPS<PushSymbolsSPSSig>(this,
619                                              &MachOPlatform::rt_pushSymbols);
620 
621   return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs));
622 }
623 
pushInitializersLoop(PushInitializersSendResultFn SendResult,JITDylibSP JD)624 void MachOPlatform::pushInitializersLoop(
625     PushInitializersSendResultFn SendResult, JITDylibSP JD) {
626   DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
627   DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap;
628   SmallVector<JITDylib *, 16> Worklist({JD.get()});
629 
630   ES.runSessionLocked([&]() {
631     while (!Worklist.empty()) {
632       // FIXME: Check for defunct dylibs.
633 
634       auto DepJD = Worklist.back();
635       Worklist.pop_back();
636 
637       // If we've already visited this JITDylib on this iteration then continue.
638       auto [It, Inserted] = JDDepMap.try_emplace(DepJD);
639       if (!Inserted)
640         continue;
641 
642       // Add dep info.
643       auto &DM = It->second;
644       DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) {
645         for (auto &KV : O) {
646           if (KV.first == DepJD)
647             continue;
648           DM.push_back(KV.first);
649           Worklist.push_back(KV.first);
650         }
651       });
652 
653       // Add any registered init symbols.
654       auto RISItr = RegisteredInitSymbols.find(DepJD);
655       if (RISItr != RegisteredInitSymbols.end()) {
656         NewInitSymbols[DepJD] = std::move(RISItr->second);
657         RegisteredInitSymbols.erase(RISItr);
658       }
659     }
660   });
661 
662   // If there are no further init symbols to look up then send the link order
663   // (as a list of header addresses) to the caller.
664   if (NewInitSymbols.empty()) {
665 
666     // To make the list intelligible to the runtime we need to convert all
667     // JITDylib pointers to their header addresses. Only include JITDylibs
668     // that appear in the JITDylibToHeaderAddr map (i.e. those that have been
669     // through setupJITDylib) -- bare JITDylibs aren't managed by the platform.
670     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
671     HeaderAddrs.reserve(JDDepMap.size());
672     {
673       std::lock_guard<std::mutex> Lock(PlatformMutex);
674       for (auto &KV : JDDepMap) {
675         auto I = JITDylibToHeaderAddr.find(KV.first);
676         if (I != JITDylibToHeaderAddr.end())
677           HeaderAddrs[KV.first] = I->second;
678       }
679     }
680 
681     // Build the dep info map to return.
682     MachOJITDylibDepInfoMap DIM;
683     DIM.reserve(JDDepMap.size());
684     for (auto &KV : JDDepMap) {
685       auto HI = HeaderAddrs.find(KV.first);
686       // Skip unmanaged JITDylibs.
687       if (HI == HeaderAddrs.end())
688         continue;
689       auto H = HI->second;
690       MachOJITDylibDepInfo DepInfo;
691       for (auto &Dep : KV.second) {
692         auto HJ = HeaderAddrs.find(Dep);
693         if (HJ != HeaderAddrs.end())
694           DepInfo.DepHeaders.push_back(HJ->second);
695       }
696       DIM.push_back(std::make_pair(H, std::move(DepInfo)));
697     }
698     SendResult(DIM);
699     return;
700   }
701 
702   // Otherwise issue a lookup and re-run this phase when it completes.
703   lookupInitSymbolsAsync(
704       [this, SendResult = std::move(SendResult), JD](Error Err) mutable {
705         if (Err)
706           SendResult(std::move(Err));
707         else
708           pushInitializersLoop(std::move(SendResult), JD);
709       },
710       ES, std::move(NewInitSymbols));
711 }
712 
rt_pushInitializers(PushInitializersSendResultFn SendResult,ExecutorAddr JDHeaderAddr)713 void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult,
714                                         ExecutorAddr JDHeaderAddr) {
715   JITDylibSP JD;
716   {
717     std::lock_guard<std::mutex> Lock(PlatformMutex);
718     auto I = HeaderAddrToJITDylib.find(JDHeaderAddr);
719     if (I != HeaderAddrToJITDylib.end())
720       JD = I->second;
721   }
722 
723   LLVM_DEBUG({
724     dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") ";
725     if (JD)
726       dbgs() << "pushing initializers for " << JD->getName() << "\n";
727     else
728       dbgs() << "No JITDylib for header address.\n";
729   });
730 
731   if (!JD) {
732     SendResult(make_error<StringError>("No JITDylib with header addr " +
733                                            formatv("{0:x}", JDHeaderAddr),
734                                        inconvertibleErrorCode()));
735     return;
736   }
737 
738   pushInitializersLoop(std::move(SendResult), JD);
739 }
740 
rt_pushSymbols(PushSymbolsInSendResultFn SendResult,ExecutorAddr Handle,const std::vector<std::pair<StringRef,bool>> & SymbolNames)741 void MachOPlatform::rt_pushSymbols(
742     PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle,
743     const std::vector<std::pair<StringRef, bool>> &SymbolNames) {
744 
745   JITDylib *JD = nullptr;
746 
747   {
748     std::lock_guard<std::mutex> Lock(PlatformMutex);
749     auto I = HeaderAddrToJITDylib.find(Handle);
750     if (I != HeaderAddrToJITDylib.end())
751       JD = I->second;
752   }
753   LLVM_DEBUG({
754     dbgs() << "MachOPlatform::rt_pushSymbols(";
755     if (JD)
756       dbgs() << "\"" << JD->getName() << "\", [ ";
757     else
758       dbgs() << "<invalid handle " << Handle << ">, [ ";
759     for (auto &Name : SymbolNames)
760       dbgs() << "\"" << Name.first << "\" ";
761     dbgs() << "])\n";
762   });
763 
764   if (!JD) {
765     SendResult(make_error<StringError>("No JITDylib associated with handle " +
766                                            formatv("{0:x}", Handle),
767                                        inconvertibleErrorCode()));
768     return;
769   }
770 
771   SymbolLookupSet LS;
772   for (auto &[Name, Required] : SymbolNames)
773     LS.add(ES.intern(Name), Required
774                                 ? SymbolLookupFlags::RequiredSymbol
775                                 : SymbolLookupFlags::WeaklyReferencedSymbol);
776 
777   ES.lookup(
778       LookupKind::DLSym, {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
779       std::move(LS), SymbolState::Ready,
780       [SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable {
781         SendResult(Result.takeError());
782       },
783       NoDependenciesToRegister);
784 }
785 
createPThreadKey()786 Expected<uint64_t> MachOPlatform::createPThreadKey() {
787   if (!CreatePThreadKey.Addr)
788     return make_error<StringError>(
789         "Attempting to create pthread key in target, but runtime support has "
790         "not been loaded yet",
791         inconvertibleErrorCode());
792 
793   Expected<uint64_t> Result(0);
794   if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>(
795           CreatePThreadKey.Addr, Result))
796     return std::move(Err);
797   return Result;
798 }
799 
modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & Config)800 void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
801     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
802     jitlink::PassConfiguration &Config) {
803 
804   using namespace jitlink;
805 
806   bool InBootstrapPhase = false;
807 
808   ExecutorAddr HeaderAddr;
809   {
810     std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
811     if (LLVM_UNLIKELY(&MR.getTargetJITDylib() == &MP.PlatformJD)) {
812       if (MP.Bootstrap) {
813         InBootstrapPhase = true;
814         ++MP.Bootstrap->ActiveGraphs;
815       }
816     }
817 
818     // Get the dso-base address if available.
819     auto I = MP.JITDylibToHeaderAddr.find(&MR.getTargetJITDylib());
820     if (I != MP.JITDylibToHeaderAddr.end())
821       HeaderAddr = I->second;
822   }
823 
824   // If we're forcing eh-frame use then discard the compact-unwind section
825   // immediately to prevent FDEs from being stripped.
826   if (MP.ForceEHFrames)
827     if (auto *CUSec = LG.findSectionByName(MachOCompactUnwindSectionName))
828       LG.removeSection(*CUSec);
829 
830   // Point the libunwind dso-base absolute symbol at the header for the
831   // JITDylib. This will prevent us from synthesizing a new header for
832   // every object.
833   if (HeaderAddr)
834     LG.addAbsoluteSymbol("__jitlink$libunwind_dso_base", HeaderAddr, 0,
835                          Linkage::Strong, Scope::Local, true);
836 
837   // If we're in the bootstrap phase then increment the active graphs.
838   if (LLVM_UNLIKELY(InBootstrapPhase))
839     Config.PostAllocationPasses.push_back([this](LinkGraph &G) {
840       return bootstrapPipelineRecordRuntimeFunctions(G);
841     });
842 
843   // --- Handle Initializers ---
844   if (auto InitSymbol = MR.getInitializerSymbol()) {
845 
846     // If the initializer symbol is the MachOHeader start symbol then just
847     // register it and then bail out -- the header materialization unit
848     // definitely doesn't need any other passes.
849     if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) {
850       Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
851         return associateJITDylibHeaderSymbol(G, MR);
852       });
853       return;
854     }
855 
856     // If the object contains an init symbol other than the header start symbol
857     // then add passes to preserve, process and register the init
858     // sections/symbols.
859     Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
860       if (auto Err = preserveImportantSections(G, MR))
861         return Err;
862       return processObjCImageInfo(G, MR);
863     });
864     Config.PostPrunePasses.push_back(
865         [this](LinkGraph &G) { return createObjCRuntimeObject(G); });
866     Config.PostAllocationPasses.push_back(
867         [this, &MR](LinkGraph &G) { return populateObjCRuntimeObject(G, MR); });
868   }
869 
870   // Insert TLV lowering at the start of the PostPrunePasses, since we want
871   // it to run before GOT/PLT lowering.
872   Config.PostPrunePasses.insert(
873       Config.PostPrunePasses.begin(),
874       [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) {
875         return fixTLVSectionsAndEdges(G, JD);
876       });
877 
878   // Add symbol table prepare and register passes: These will add strings for
879   // all symbols to the c-strings section, and build a symbol table registration
880   // call.
881   auto JITSymTabInfo = std::make_shared<JITSymTabVector>();
882   Config.PostPrunePasses.push_back([this, JITSymTabInfo](LinkGraph &G) {
883     return prepareSymbolTableRegistration(G, *JITSymTabInfo);
884   });
885   Config.PostFixupPasses.push_back([this, &MR, JITSymTabInfo,
886                                     InBootstrapPhase](LinkGraph &G) {
887     return addSymbolTableRegistration(G, MR, *JITSymTabInfo, InBootstrapPhase);
888   });
889 
890   // Add a pass to register the final addresses of any special sections in the
891   // object with the runtime.
892   Config.PostAllocationPasses.push_back([this, &JD = MR.getTargetJITDylib(),
893                                          HeaderAddr,
894                                          InBootstrapPhase](LinkGraph &G) {
895     return registerObjectPlatformSections(G, JD, HeaderAddr, InBootstrapPhase);
896   });
897 
898   // If we're in the bootstrap phase then steal allocation actions and then
899   // decrement the active graphs.
900   if (InBootstrapPhase)
901     Config.PostFixupPasses.push_back(
902         [this](LinkGraph &G) { return bootstrapPipelineEnd(G); });
903 }
904 
905 Error MachOPlatform::MachOPlatformPlugin::
bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph & G)906     bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) {
907   // Record bootstrap function names.
908   std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = {
909       {*MP.MachOHeaderStartSymbol, &MP.Bootstrap->MachOHeaderAddr},
910       {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr},
911       {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr},
912       {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr},
913       {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr},
914       {*MP.RegisterObjectSymbolTable.Name, &MP.RegisterObjectSymbolTable.Addr},
915       {*MP.DeregisterObjectSymbolTable.Name,
916        &MP.DeregisterObjectSymbolTable.Addr},
917       {*MP.RegisterObjectPlatformSections.Name,
918        &MP.RegisterObjectPlatformSections.Addr},
919       {*MP.DeregisterObjectPlatformSections.Name,
920        &MP.DeregisterObjectPlatformSections.Addr},
921       {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr},
922       {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr},
923       {*MP.DeregisterObjCRuntimeObject.Name,
924        &MP.DeregisterObjCRuntimeObject.Addr}};
925 
926   bool RegisterMachOHeader = false;
927 
928   for (auto *Sym : G.defined_symbols()) {
929     for (auto &RTSym : RuntimeSymbols) {
930       if (Sym->hasName() && *Sym->getName() == RTSym.first) {
931         if (*RTSym.second)
932           return make_error<StringError>(
933               "Duplicate " + RTSym.first +
934                   " detected during MachOPlatform bootstrap",
935               inconvertibleErrorCode());
936 
937         if (Sym->getName() == MP.MachOHeaderStartSymbol)
938           RegisterMachOHeader = true;
939 
940         *RTSym.second = Sym->getAddress();
941       }
942     }
943   }
944 
945   if (RegisterMachOHeader) {
946     // If this graph defines the macho header symbol then create the internal
947     // mapping between it and PlatformJD.
948     std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
949     MP.JITDylibToHeaderAddr[&MP.PlatformJD] = MP.Bootstrap->MachOHeaderAddr;
950     MP.HeaderAddrToJITDylib[MP.Bootstrap->MachOHeaderAddr] = &MP.PlatformJD;
951   }
952 
953   return Error::success();
954 }
955 
bootstrapPipelineEnd(jitlink::LinkGraph & G)956 Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd(
957     jitlink::LinkGraph &G) {
958   std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
959 
960   --MP.Bootstrap->ActiveGraphs;
961   // Notify Bootstrap->CV while holding the mutex because the mutex is
962   // also keeping Bootstrap->CV alive.
963   if (MP.Bootstrap->ActiveGraphs == 0)
964     MP.Bootstrap->CV.notify_all();
965   return Error::success();
966 }
967 
associateJITDylibHeaderSymbol(jitlink::LinkGraph & G,MaterializationResponsibility & MR)968 Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
969     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
970   auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) {
971     return Sym->getName() == MP.MachOHeaderStartSymbol;
972   });
973   assert(I != G.defined_symbols().end() && "Missing MachO header start symbol");
974 
975   auto &JD = MR.getTargetJITDylib();
976   std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
977   auto HeaderAddr = (*I)->getAddress();
978   MP.JITDylibToHeaderAddr[&JD] = HeaderAddr;
979   MP.HeaderAddrToJITDylib[HeaderAddr] = &JD;
980   // We can unconditionally add these actions to the Graph because this pass
981   // isn't used during bootstrap.
982   G.allocActions().push_back(
983       {cantFail(
984            WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>(
985                MP.RegisterJITDylib.Addr, JD.getName(), HeaderAddr)),
986        cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
987            MP.DeregisterJITDylib.Addr, HeaderAddr))});
988   return Error::success();
989 }
990 
preserveImportantSections(jitlink::LinkGraph & G,MaterializationResponsibility & MR)991 Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
992     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
993   // __objc_imageinfo is "important": we want to preserve it and record its
994   // address in the first graph that it appears in, then verify and discard it
995   // in all subsequent graphs. In this pass we preserve unconditionally -- we'll
996   // manually throw it away in the processObjCImageInfo pass.
997   if (auto *ObjCImageInfoSec =
998           G.findSectionByName(MachOObjCImageInfoSectionName)) {
999     if (ObjCImageInfoSec->blocks_size() != 1)
1000       return make_error<StringError>(
1001           "In " + G.getName() +
1002               "__DATA,__objc_imageinfo contains multiple blocks",
1003           inconvertibleErrorCode());
1004     G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,
1005                          true);
1006 
1007     for (auto *B : ObjCImageInfoSec->blocks())
1008       if (!B->edges_empty())
1009         return make_error<StringError>("In " + G.getName() + ", " +
1010                                            MachOObjCImageInfoSectionName +
1011                                            " contains references to symbols",
1012                                        inconvertibleErrorCode());
1013   }
1014 
1015   // Init sections are important: We need to preserve them and so that their
1016   // addresses can be captured and reported to the ORC runtime in
1017   // registerObjectPlatformSections.
1018   if (const auto &InitSymName = MR.getInitializerSymbol()) {
1019 
1020     jitlink::Symbol *InitSym = nullptr;
1021     for (auto &InitSectionName : MachOInitSectionNames) {
1022       // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may
1023       // remove it later.
1024       if (InitSectionName == MachOObjCImageInfoSectionName)
1025         continue;
1026 
1027       // Skip non-init sections.
1028       auto *InitSection = G.findSectionByName(InitSectionName);
1029       if (!InitSection || InitSection->empty())
1030         continue;
1031 
1032       // Create the init symbol if it has not been created already and attach it
1033       // to the first block.
1034       if (!InitSym) {
1035         auto &B = **InitSection->blocks().begin();
1036         InitSym = &G.addDefinedSymbol(
1037             B, 0, *InitSymName, B.getSize(), jitlink::Linkage::Strong,
1038             jitlink::Scope::SideEffectsOnly, false, true);
1039       }
1040 
1041       // Add keep-alive edges to anonymous symbols in all other init blocks.
1042       for (auto *B : InitSection->blocks()) {
1043         if (B == &InitSym->getBlock())
1044           continue;
1045 
1046         auto &S = G.addAnonymousSymbol(*B, 0, B->getSize(), false, true);
1047         InitSym->getBlock().addEdge(jitlink::Edge::KeepAlive, 0, S, 0);
1048       }
1049     }
1050   }
1051 
1052   return Error::success();
1053 }
1054 
processObjCImageInfo(jitlink::LinkGraph & G,MaterializationResponsibility & MR)1055 Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
1056     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
1057 
1058   // If there's an ObjC imagine info then either
1059   //   (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
1060   //       this case we name and record it.
1061   // OR
1062   //   (2) We already have a recorded __objc_imageinfo for this JITDylib,
1063   //       in which case we just verify it.
1064   auto *ObjCImageInfo = G.findSectionByName(MachOObjCImageInfoSectionName);
1065   if (!ObjCImageInfo)
1066     return Error::success();
1067 
1068   auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
1069 
1070   // Check that the section is not empty if present.
1071   if (ObjCImageInfoBlocks.empty())
1072     return make_error<StringError>("Empty " + MachOObjCImageInfoSectionName +
1073                                        " section in " + G.getName(),
1074                                    inconvertibleErrorCode());
1075 
1076   // Check that there's only one block in the section.
1077   if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
1078     return make_error<StringError>("Multiple blocks in " +
1079                                        MachOObjCImageInfoSectionName +
1080                                        " section in " + G.getName(),
1081                                    inconvertibleErrorCode());
1082 
1083   // Check that the __objc_imageinfo section is unreferenced.
1084   // FIXME: We could optimize this check if Symbols had a ref-count.
1085   for (auto &Sec : G.sections()) {
1086     if (&Sec != ObjCImageInfo)
1087       for (auto *B : Sec.blocks())
1088         for (auto &E : B->edges())
1089           if (E.getTarget().isDefined() &&
1090               &E.getTarget().getSection() == ObjCImageInfo)
1091             return make_error<StringError>(MachOObjCImageInfoSectionName +
1092                                                " is referenced within file " +
1093                                                G.getName(),
1094                                            inconvertibleErrorCode());
1095   }
1096 
1097   auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
1098   auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
1099   auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
1100   auto Flags =
1101       support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
1102 
1103   // Lock the mutex while we verify / update the ObjCImageInfos map.
1104   std::lock_guard<std::mutex> Lock(PluginMutex);
1105 
1106   auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
1107   if (ObjCImageInfoItr != ObjCImageInfos.end()) {
1108     // We've already registered an __objc_imageinfo section. Verify the
1109     // content of this new section matches, then delete it.
1110     if (ObjCImageInfoItr->second.Version != Version)
1111       return make_error<StringError>(
1112           "ObjC version in " + G.getName() +
1113               " does not match first registered version",
1114           inconvertibleErrorCode());
1115     if (ObjCImageInfoItr->second.Flags != Flags)
1116       if (Error E = mergeImageInfoFlags(G, MR, ObjCImageInfoItr->second, Flags))
1117         return E;
1118 
1119     // __objc_imageinfo is valid. Delete the block.
1120     for (auto *S : ObjCImageInfo->symbols())
1121       G.removeDefinedSymbol(*S);
1122     G.removeBlock(ObjCImageInfoBlock);
1123   } else {
1124     LLVM_DEBUG({
1125       dbgs() << "MachOPlatform: Registered __objc_imageinfo for "
1126              << MR.getTargetJITDylib().getName() << " in " << G.getName()
1127              << "; flags = " << formatv("{0:x4}", Flags) << "\n";
1128     });
1129     // We haven't registered an __objc_imageinfo section yet. Register and
1130     // move on. The section should already be marked no-dead-strip.
1131     G.addDefinedSymbol(ObjCImageInfoBlock, 0, ObjCImageInfoSymbolName,
1132                        ObjCImageInfoBlock.getSize(), jitlink::Linkage::Strong,
1133                        jitlink::Scope::Hidden, false, true);
1134     if (auto Err = MR.defineMaterializing(
1135             {{MR.getExecutionSession().intern(ObjCImageInfoSymbolName),
1136               JITSymbolFlags()}}))
1137       return Err;
1138     ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags, false};
1139   }
1140 
1141   return Error::success();
1142 }
1143 
mergeImageInfoFlags(jitlink::LinkGraph & G,MaterializationResponsibility & MR,ObjCImageInfo & Info,uint32_t NewFlags)1144 Error MachOPlatform::MachOPlatformPlugin::mergeImageInfoFlags(
1145     jitlink::LinkGraph &G, MaterializationResponsibility &MR,
1146     ObjCImageInfo &Info, uint32_t NewFlags) {
1147   if (Info.Flags == NewFlags)
1148     return Error::success();
1149 
1150   ObjCImageInfoFlags Old(Info.Flags);
1151   ObjCImageInfoFlags New(NewFlags);
1152 
1153   // Check for incompatible flags.
1154   if (Old.SwiftABIVersion && New.SwiftABIVersion &&
1155       Old.SwiftABIVersion != New.SwiftABIVersion)
1156     return make_error<StringError>("Swift ABI version in " + G.getName() +
1157                                        " does not match first registered flags",
1158                                    inconvertibleErrorCode());
1159 
1160   // HasCategoryClassProperties and HasSignedObjCClassROs can be disabled before
1161   // they are registered, if necessary, but once they are in use must be
1162   // supported by subsequent objects.
1163   if (Info.Finalized && Old.HasCategoryClassProperties &&
1164       !New.HasCategoryClassProperties)
1165     return make_error<StringError>("ObjC category class property support in " +
1166                                        G.getName() +
1167                                        " does not match first registered flags",
1168                                    inconvertibleErrorCode());
1169   if (Info.Finalized && Old.HasSignedObjCClassROs && !New.HasSignedObjCClassROs)
1170     return make_error<StringError>("ObjC class_ro_t pointer signing in " +
1171                                        G.getName() +
1172                                        " does not match first registered flags",
1173                                    inconvertibleErrorCode());
1174 
1175   // If we cannot change the flags, ignore any remaining differences. Adding
1176   // Swift or changing its version are unlikely to cause problems in practice.
1177   if (Info.Finalized)
1178     return Error::success();
1179 
1180   // Use the minimum Swift version.
1181   if (Old.SwiftVersion && New.SwiftVersion)
1182     New.SwiftVersion = std::min(Old.SwiftVersion, New.SwiftVersion);
1183   else if (Old.SwiftVersion)
1184     New.SwiftVersion = Old.SwiftVersion;
1185   // Add a Swift ABI version if it was pure objc before.
1186   if (!New.SwiftABIVersion)
1187     New.SwiftABIVersion = Old.SwiftABIVersion;
1188   // Disable class properties if any object does not support it.
1189   if (Old.HasCategoryClassProperties != New.HasCategoryClassProperties)
1190     New.HasCategoryClassProperties = false;
1191   // Disable signed class ro data if any object does not support it.
1192   if (Old.HasSignedObjCClassROs != New.HasSignedObjCClassROs)
1193     New.HasSignedObjCClassROs = false;
1194 
1195   LLVM_DEBUG({
1196     dbgs() << "MachOPlatform: Merging __objc_imageinfo flags for "
1197            << MR.getTargetJITDylib().getName() << " (was "
1198            << formatv("{0:x4}", Old.rawFlags()) << ")"
1199            << " with " << G.getName() << " (" << formatv("{0:x4}", NewFlags)
1200            << ")"
1201            << " -> " << formatv("{0:x4}", New.rawFlags()) << "\n";
1202   });
1203 
1204   Info.Flags = New.rawFlags();
1205   return Error::success();
1206 }
1207 
fixTLVSectionsAndEdges(jitlink::LinkGraph & G,JITDylib & JD)1208 Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges(
1209     jitlink::LinkGraph &G, JITDylib &JD) {
1210   auto TLVBootStrapSymbolName = G.intern("__tlv_bootstrap");
1211   // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr.
1212   for (auto *Sym : G.external_symbols())
1213     if (Sym->getName() == TLVBootStrapSymbolName) {
1214       auto TLSGetADDR =
1215           MP.getExecutionSession().intern("___orc_rt_macho_tlv_get_addr");
1216       Sym->setName(std::move(TLSGetADDR));
1217       break;
1218     }
1219 
1220   // Store key in __thread_vars struct fields.
1221   if (auto *ThreadDataSec = G.findSectionByName(MachOThreadVarsSectionName)) {
1222     std::optional<uint64_t> Key;
1223     {
1224       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1225       auto I = MP.JITDylibToPThreadKey.find(&JD);
1226       if (I != MP.JITDylibToPThreadKey.end())
1227         Key = I->second;
1228     }
1229 
1230     if (!Key) {
1231       if (auto KeyOrErr = MP.createPThreadKey())
1232         Key = *KeyOrErr;
1233       else
1234         return KeyOrErr.takeError();
1235     }
1236 
1237     uint64_t PlatformKeyBits =
1238         support::endian::byte_swap(*Key, G.getEndianness());
1239 
1240     for (auto *B : ThreadDataSec->blocks()) {
1241       if (B->getSize() != 3 * G.getPointerSize())
1242         return make_error<StringError>("__thread_vars block at " +
1243                                            formatv("{0:x}", B->getAddress()) +
1244                                            " has unexpected size",
1245                                        inconvertibleErrorCode());
1246 
1247       auto NewBlockContent = G.allocateBuffer(B->getSize());
1248       llvm::copy(B->getContent(), NewBlockContent.data());
1249       memcpy(NewBlockContent.data() + G.getPointerSize(), &PlatformKeyBits,
1250              G.getPointerSize());
1251       B->setContent(NewBlockContent);
1252     }
1253   }
1254 
1255   // Transform any TLV edges into GOT edges.
1256   for (auto *B : G.blocks())
1257     for (auto &E : B->edges())
1258       if (E.getKind() ==
1259           jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable)
1260         E.setKind(jitlink::x86_64::
1261                       RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable);
1262 
1263   return Error::success();
1264 }
1265 
1266 std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections>
findUnwindSectionInfo(jitlink::LinkGraph & G)1267 MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo(
1268     jitlink::LinkGraph &G) {
1269   using namespace jitlink;
1270 
1271   UnwindSections US;
1272 
1273   // ScanSection records a section range and adds any executable blocks that
1274   // that section points to to the CodeBlocks vector.
1275   SmallVector<Block *> CodeBlocks;
1276   auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange,
1277                                    auto AddCodeBlocks) {
1278     if (Sec.blocks().empty())
1279       return;
1280     SecRange = (*Sec.blocks().begin())->getRange();
1281     for (auto *B : Sec.blocks()) {
1282       auto R = B->getRange();
1283       SecRange.Start = std::min(SecRange.Start, R.Start);
1284       SecRange.End = std::max(SecRange.End, R.End);
1285       AddCodeBlocks(*B);
1286     }
1287   };
1288 
1289   if (Section *EHFrameSec = G.findSectionByName(MachOEHFrameSectionName)) {
1290     ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection, [&](Block &B) {
1291       if (auto *Fn = jitlink::EHFrameCFIBlockInspector::FromEdgeScan(B)
1292                          .getPCBeginEdge())
1293         if (Fn->getTarget().isDefined())
1294           CodeBlocks.push_back(&Fn->getTarget().getBlock());
1295     });
1296   }
1297 
1298   if (Section *CUInfoSec = G.findSectionByName(MachOUnwindInfoSectionName)) {
1299     ScanUnwindInfoSection(
1300         *CUInfoSec, US.CompactUnwindSection, [&](Block &B) {
1301           for (auto &E : B.edges()) {
1302             assert(E.getTarget().isDefined() &&
1303                    "unwind-info record edge has external target");
1304             assert(E.getKind() == Edge::KeepAlive &&
1305                    "unwind-info record has unexpected edge kind");
1306             CodeBlocks.push_back(&E.getTarget().getBlock());
1307           }
1308         });
1309   }
1310 
1311   // If we didn't find any pointed-to code-blocks then there's no need to
1312   // register any info.
1313   if (CodeBlocks.empty())
1314     return std::nullopt;
1315 
1316   // We have info to register. Sort the code blocks into address order and
1317   // build a list of contiguous address ranges covering them all.
1318   llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) {
1319     return LHS->getAddress() < RHS->getAddress();
1320   });
1321   for (auto *B : CodeBlocks) {
1322     if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress())
1323       US.CodeRanges.push_back(B->getRange());
1324     else
1325       US.CodeRanges.back().End = B->getRange().End;
1326   }
1327 
1328   LLVM_DEBUG({
1329     dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n"
1330            << "  DWARF: ";
1331     if (US.DwarfSection.Start)
1332       dbgs() << US.DwarfSection << "\n";
1333     else
1334       dbgs() << "none\n";
1335     dbgs() << "  Compact-unwind: ";
1336     if (US.CompactUnwindSection.Start)
1337       dbgs() << US.CompactUnwindSection << "\n";
1338     else
1339       dbgs() << "none\n"
1340              << "for code ranges:\n";
1341     for (auto &CR : US.CodeRanges)
1342       dbgs() << "  " << CR << "\n";
1343     if (US.CodeRanges.size() >= G.sections_size())
1344       dbgs() << "WARNING: High number of discontiguous code ranges! "
1345                 "Padding may be interfering with coalescing.\n";
1346   });
1347 
1348   return US;
1349 }
1350 
registerObjectPlatformSections(jitlink::LinkGraph & G,JITDylib & JD,ExecutorAddr HeaderAddr,bool InBootstrapPhase)1351 Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
1352     jitlink::LinkGraph &G, JITDylib &JD, ExecutorAddr HeaderAddr,
1353     bool InBootstrapPhase) {
1354 
1355   // Get a pointer to the thread data section if there is one. It will be used
1356   // below.
1357   jitlink::Section *ThreadDataSection =
1358       G.findSectionByName(MachOThreadDataSectionName);
1359 
1360   // Handle thread BSS section if there is one.
1361   if (auto *ThreadBSSSection = G.findSectionByName(MachOThreadBSSSectionName)) {
1362     // If there's already a thread data section in this graph then merge the
1363     // thread BSS section content into it, otherwise just treat the thread
1364     // BSS section as the thread data section.
1365     if (ThreadDataSection)
1366       G.mergeSections(*ThreadDataSection, *ThreadBSSSection);
1367     else
1368       ThreadDataSection = ThreadBSSSection;
1369   }
1370 
1371   SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs;
1372 
1373   // Collect data sections to register.
1374   StringRef DataSections[] = {MachODataDataSectionName,
1375                               MachODataCommonSectionName,
1376                               MachOEHFrameSectionName};
1377   for (auto &SecName : DataSections) {
1378     if (auto *Sec = G.findSectionByName(SecName)) {
1379       jitlink::SectionRange R(*Sec);
1380       if (!R.empty())
1381         MachOPlatformSecs.push_back({SecName, R.getRange()});
1382     }
1383   }
1384 
1385   // Having merged thread BSS (if present) and thread data (if present),
1386   // record the resulting section range.
1387   if (ThreadDataSection) {
1388     jitlink::SectionRange R(*ThreadDataSection);
1389     if (!R.empty())
1390       MachOPlatformSecs.push_back({MachOThreadDataSectionName, R.getRange()});
1391   }
1392 
1393   // If any platform sections were found then add an allocation action to call
1394   // the registration function.
1395   StringRef PlatformSections[] = {MachOModInitFuncSectionName,
1396                                   ObjCRuntimeObjectSectionName};
1397 
1398   for (auto &SecName : PlatformSections) {
1399     auto *Sec = G.findSectionByName(SecName);
1400     if (!Sec)
1401       continue;
1402     jitlink::SectionRange R(*Sec);
1403     if (R.empty())
1404       continue;
1405 
1406     MachOPlatformSecs.push_back({SecName, R.getRange()});
1407   }
1408 
1409   std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange,
1410                            ExecutorAddrRange>>
1411       UnwindInfo;
1412   if (auto UI = findUnwindSectionInfo(G))
1413     UnwindInfo = std::make_tuple(std::move(UI->CodeRanges), UI->DwarfSection,
1414                                  UI->CompactUnwindSection);
1415 
1416   if (!MachOPlatformSecs.empty() || UnwindInfo) {
1417     // Dump the scraped inits.
1418     LLVM_DEBUG({
1419       dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
1420       for (auto &KV : MachOPlatformSecs)
1421         dbgs() << "  " << KV.first << ": " << KV.second << "\n";
1422     });
1423 
1424     assert(HeaderAddr && "Null header registered for JD");
1425     using SPSRegisterObjectPlatformSectionsArgs = SPSArgList<
1426         SPSExecutorAddr,
1427         SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>,
1428                              SPSExecutorAddrRange, SPSExecutorAddrRange>>,
1429         SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>;
1430 
1431     AllocActionCallPair AllocActions = {
1432         cantFail(
1433             WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1434                 MP.RegisterObjectPlatformSections.Addr, HeaderAddr, UnwindInfo,
1435                 MachOPlatformSecs)),
1436         cantFail(
1437             WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>(
1438                 MP.DeregisterObjectPlatformSections.Addr, HeaderAddr,
1439                 UnwindInfo, MachOPlatformSecs))};
1440 
1441     if (LLVM_LIKELY(!InBootstrapPhase))
1442       G.allocActions().push_back(std::move(AllocActions));
1443     else {
1444       std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1445       MP.Bootstrap->DeferredAAs.push_back(std::move(AllocActions));
1446     }
1447   }
1448 
1449   return Error::success();
1450 }
1451 
createObjCRuntimeObject(jitlink::LinkGraph & G)1452 Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
1453     jitlink::LinkGraph &G) {
1454 
1455   bool NeedTextSegment = false;
1456   size_t NumRuntimeSections = 0;
1457 
1458   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
1459     if (G.findSectionByName(ObjCRuntimeSectionName))
1460       ++NumRuntimeSections;
1461 
1462   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1463     if (G.findSectionByName(ObjCRuntimeSectionName)) {
1464       ++NumRuntimeSections;
1465       NeedTextSegment = true;
1466     }
1467   }
1468 
1469   // Early out for no runtime sections.
1470   if (NumRuntimeSections == 0)
1471     return Error::success();
1472 
1473   // If there were any runtime sections then we need to add an __objc_imageinfo
1474   // section.
1475   ++NumRuntimeSections;
1476 
1477   size_t MachOSize = sizeof(MachO::mach_header_64) +
1478                      (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
1479                      NumRuntimeSections * sizeof(MachO::section_64);
1480 
1481   auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
1482                               MemProt::Read | MemProt::Write);
1483   G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
1484 
1485   return Error::success();
1486 }
1487 
populateObjCRuntimeObject(jitlink::LinkGraph & G,MaterializationResponsibility & MR)1488 Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
1489     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
1490 
1491   auto *ObjCRuntimeObjectSec =
1492       G.findSectionByName(ObjCRuntimeObjectSectionName);
1493 
1494   if (!ObjCRuntimeObjectSec)
1495     return Error::success();
1496 
1497   switch (G.getTargetTriple().getArch()) {
1498   case Triple::aarch64:
1499   case Triple::x86_64:
1500     // Supported.
1501     break;
1502   default:
1503     return make_error<StringError>("Unrecognized MachO arch in triple " +
1504                                        G.getTargetTriple().str(),
1505                                    inconvertibleErrorCode());
1506   }
1507 
1508   auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
1509 
1510   struct SecDesc {
1511     MachO::section_64 Sec;
1512     unique_function<void(size_t RecordOffset)> AddFixups;
1513   };
1514 
1515   std::vector<SecDesc> TextSections, DataSections;
1516   auto AddSection = [&](SecDesc &SD, jitlink::Section &GraphSec) {
1517     jitlink::SectionRange SR(GraphSec);
1518     StringRef FQName = GraphSec.getName();
1519     memset(&SD.Sec, 0, sizeof(MachO::section_64));
1520     memcpy(SD.Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7);
1521     memcpy(SD.Sec.segname, FQName.data(), 6);
1522     SD.Sec.addr = SR.getStart() - SecBlock.getAddress();
1523     SD.Sec.size = SR.getSize();
1524     SD.Sec.flags = MachO::S_REGULAR;
1525   };
1526 
1527   // Add the __objc_imageinfo section.
1528   {
1529     DataSections.push_back({});
1530     auto &SD = DataSections.back();
1531     memset(&SD.Sec, 0, sizeof(SD.Sec));
1532     memcpy(SD.Sec.sectname, "__objc_imageinfo", 16);
1533     strcpy(SD.Sec.segname, "__DATA");
1534     SD.Sec.size = 8;
1535     jitlink::Symbol *ObjCImageInfoSym = nullptr;
1536     SD.AddFixups = [&, ObjCImageInfoSym](size_t RecordOffset) mutable {
1537       auto PointerEdge = getPointerEdgeKind(G);
1538 
1539       // Look for an existing __objc_imageinfo symbol.
1540       if (!ObjCImageInfoSym) {
1541         auto Name = G.intern(ObjCImageInfoSymbolName);
1542         ObjCImageInfoSym = G.findExternalSymbolByName(Name);
1543         if (!ObjCImageInfoSym)
1544           ObjCImageInfoSym = G.findAbsoluteSymbolByName(Name);
1545         if (!ObjCImageInfoSym) {
1546           ObjCImageInfoSym = G.findDefinedSymbolByName(Name);
1547           if (ObjCImageInfoSym) {
1548             std::optional<uint32_t> Flags;
1549             {
1550               std::lock_guard<std::mutex> Lock(PluginMutex);
1551               auto It = ObjCImageInfos.find(&MR.getTargetJITDylib());
1552               if (It != ObjCImageInfos.end()) {
1553                 It->second.Finalized = true;
1554                 Flags = It->second.Flags;
1555               }
1556             }
1557 
1558             if (Flags) {
1559               // We own the definition of __objc_image_info; write the final
1560               // merged flags value.
1561               auto Content = ObjCImageInfoSym->getBlock().getMutableContent(G);
1562               assert(
1563                   Content.size() == 8 &&
1564                   "__objc_image_info size should have been verified already");
1565               support::endian::write32(&Content[4], *Flags, G.getEndianness());
1566             }
1567           }
1568         }
1569         if (!ObjCImageInfoSym)
1570           ObjCImageInfoSym = &G.addExternalSymbol(std::move(Name), 8, false);
1571       }
1572 
1573       SecBlock.addEdge(PointerEdge,
1574                        RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec),
1575                        *ObjCImageInfoSym, -SecBlock.getAddress().getValue());
1576     };
1577   }
1578 
1579   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
1580     if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1581       DataSections.push_back({});
1582       AddSection(DataSections.back(), *GraphSec);
1583     }
1584   }
1585 
1586   for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
1587     if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
1588       TextSections.push_back({});
1589       AddSection(TextSections.back(), *GraphSec);
1590     }
1591   }
1592 
1593   assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
1594          "Unexpected number of blocks in runtime sections object");
1595 
1596   // Build the header struct up-front. This also gives us a chance to check
1597   // that the triple is supported, which we'll assume below.
1598   MachO::mach_header_64 Hdr;
1599   Hdr.magic = MachO::MH_MAGIC_64;
1600   switch (G.getTargetTriple().getArch()) {
1601   case Triple::aarch64:
1602     Hdr.cputype = MachO::CPU_TYPE_ARM64;
1603     Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
1604     break;
1605   case Triple::x86_64:
1606     Hdr.cputype = MachO::CPU_TYPE_X86_64;
1607     Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
1608     break;
1609   default:
1610     llvm_unreachable("Unsupported architecture");
1611   }
1612 
1613   Hdr.filetype = MachO::MH_DYLIB;
1614   Hdr.ncmds = 1 + !TextSections.empty();
1615   Hdr.sizeofcmds =
1616       Hdr.ncmds * sizeof(MachO::segment_command_64) +
1617       (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);
1618   Hdr.flags = 0;
1619   Hdr.reserved = 0;
1620 
1621   auto SecContent = SecBlock.getAlreadyMutableContent();
1622   char *P = SecContent.data();
1623   auto WriteMachOStruct = [&](auto S) {
1624     if (G.getEndianness() != llvm::endianness::native)
1625       MachO::swapStruct(S);
1626     memcpy(P, &S, sizeof(S));
1627     P += sizeof(S);
1628   };
1629 
1630   auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) {
1631     MachO::segment_command_64 SegLC;
1632     memset(&SegLC, 0, sizeof(SegLC));
1633     memcpy(SegLC.segname, Name.data(), Name.size());
1634     SegLC.cmd = MachO::LC_SEGMENT_64;
1635     SegLC.cmdsize = sizeof(MachO::segment_command_64) +
1636                     Secs.size() * sizeof(MachO::section_64);
1637     SegLC.nsects = Secs.size();
1638     WriteMachOStruct(SegLC);
1639     for (auto &SD : Secs) {
1640       if (SD.AddFixups)
1641         SD.AddFixups(P - SecContent.data());
1642       WriteMachOStruct(SD.Sec);
1643     }
1644   };
1645 
1646   WriteMachOStruct(Hdr);
1647   if (!TextSections.empty())
1648     WriteSegment("__TEXT", TextSections);
1649   if (!DataSections.empty())
1650     WriteSegment("__DATA", DataSections);
1651 
1652   assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
1653   return Error::success();
1654 }
1655 
prepareSymbolTableRegistration(jitlink::LinkGraph & G,JITSymTabVector & JITSymTabInfo)1656 Error MachOPlatform::MachOPlatformPlugin::prepareSymbolTableRegistration(
1657     jitlink::LinkGraph &G, JITSymTabVector &JITSymTabInfo) {
1658 
1659   auto *CStringSec = G.findSectionByName(MachOCStringSectionName);
1660   if (!CStringSec)
1661     CStringSec = &G.createSection(MachOCStringSectionName,
1662                                   MemProt::Read | MemProt::Exec);
1663 
1664   // Make a map of existing strings so that we can re-use them:
1665   DenseMap<StringRef, jitlink::Symbol *> ExistingStrings;
1666   for (auto *Sym : CStringSec->symbols()) {
1667 
1668     // The LinkGraph builder should have created single strings blocks, and all
1669     // plugins should have maintained this invariant.
1670     auto Content = Sym->getBlock().getContent();
1671     ExistingStrings.insert(
1672         std::make_pair(StringRef(Content.data(), Content.size()), Sym));
1673   }
1674 
1675   // Add all symbol names to the string section, and record the symbols for
1676   // those names.
1677   {
1678     SmallVector<jitlink::Symbol *> SymsToProcess;
1679     llvm::append_range(SymsToProcess, G.defined_symbols());
1680     llvm::append_range(SymsToProcess, G.absolute_symbols());
1681 
1682     for (auto *Sym : SymsToProcess) {
1683       if (!Sym->hasName())
1684         continue;
1685 
1686       auto I = ExistingStrings.find(*Sym->getName());
1687       if (I == ExistingStrings.end()) {
1688         auto &NameBlock = G.createMutableContentBlock(
1689             *CStringSec, G.allocateCString(*Sym->getName()),
1690             orc::ExecutorAddr(), 1, 0);
1691         auto &SymbolNameSym = G.addAnonymousSymbol(
1692             NameBlock, 0, NameBlock.getSize(), false, true);
1693         JITSymTabInfo.push_back({Sym, &SymbolNameSym});
1694       } else
1695         JITSymTabInfo.push_back({Sym, I->second});
1696     }
1697   }
1698 
1699   return Error::success();
1700 }
1701 
addSymbolTableRegistration(jitlink::LinkGraph & G,MaterializationResponsibility & MR,JITSymTabVector & JITSymTabInfo,bool InBootstrapPhase)1702 Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration(
1703     jitlink::LinkGraph &G, MaterializationResponsibility &MR,
1704     JITSymTabVector &JITSymTabInfo, bool InBootstrapPhase) {
1705 
1706   ExecutorAddr HeaderAddr;
1707   {
1708     std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1709     auto I = MP.JITDylibToHeaderAddr.find(&MR.getTargetJITDylib());
1710     assert(I != MP.JITDylibToHeaderAddr.end() && "No header registered for JD");
1711     assert(I->second && "Null header registered for JD");
1712     HeaderAddr = I->second;
1713   }
1714 
1715   if (LLVM_UNLIKELY(InBootstrapPhase)) {
1716     // If we're in the bootstrap phase then just record these symbols in the
1717     // bootstrap object and then bail out -- registration will be attached to
1718     // the bootstrap graph.
1719     std::lock_guard<std::mutex> Lock(MP.PlatformMutex);
1720     auto &SymTab = MP.Bootstrap->SymTab;
1721     for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo)
1722       SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(),
1723                         flagsForSymbol(*OriginalSymbol)});
1724     return Error::success();
1725   }
1726 
1727   SymbolTableVector SymTab;
1728   for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo)
1729     SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(),
1730                       flagsForSymbol(*OriginalSymbol)});
1731 
1732   G.allocActions().push_back(
1733       {cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
1734            MP.RegisterObjectSymbolTable.Addr, HeaderAddr, SymTab)),
1735        cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
1736            MP.DeregisterObjectSymbolTable.Addr, HeaderAddr, SymTab))});
1737 
1738   return Error::success();
1739 }
1740 
1741 template <typename MachOTraits>
createHeaderBlock(MachOPlatform & MOP,const MachOPlatform::HeaderOptions & Opts,JITDylib & JD,jitlink::LinkGraph & G,jitlink::Section & HeaderSection)1742 jitlink::Block &createHeaderBlock(MachOPlatform &MOP,
1743                                   const MachOPlatform::HeaderOptions &Opts,
1744                                   JITDylib &JD, jitlink::LinkGraph &G,
1745                                   jitlink::Section &HeaderSection) {
1746   auto HdrInfo =
1747       getMachOHeaderInfoFromTriple(MOP.getExecutionSession().getTargetTriple());
1748   MachOBuilder<MachOTraits> B(HdrInfo.PageSize);
1749 
1750   B.Header.filetype = MachO::MH_DYLIB;
1751   B.Header.cputype = HdrInfo.CPUType;
1752   B.Header.cpusubtype = HdrInfo.CPUSubType;
1753 
1754   if (Opts.IDDylib)
1755     B.template addLoadCommand<MachO::LC_ID_DYLIB>(
1756         Opts.IDDylib->Name, Opts.IDDylib->Timestamp,
1757         Opts.IDDylib->CurrentVersion, Opts.IDDylib->CompatibilityVersion);
1758   else
1759     B.template addLoadCommand<MachO::LC_ID_DYLIB>(JD.getName(), 0, 0, 0);
1760 
1761   for (auto &BV : Opts.BuildVersions)
1762     B.template addLoadCommand<MachO::LC_BUILD_VERSION>(
1763         BV.Platform, BV.MinOS, BV.SDK, static_cast<uint32_t>(0));
1764 
1765   using LoadKind = MachOPlatform::HeaderOptions::LoadDylibCmd::LoadKind;
1766   for (auto &LD : Opts.LoadDylibs) {
1767     switch (LD.K) {
1768     case LoadKind::Default:
1769       B.template addLoadCommand<MachO::LC_LOAD_DYLIB>(
1770           LD.D.Name, LD.D.Timestamp, LD.D.CurrentVersion,
1771           LD.D.CompatibilityVersion);
1772       break;
1773     case LoadKind::Weak:
1774       B.template addLoadCommand<MachO::LC_LOAD_WEAK_DYLIB>(
1775           LD.D.Name, LD.D.Timestamp, LD.D.CurrentVersion,
1776           LD.D.CompatibilityVersion);
1777       break;
1778     }
1779   }
1780   for (auto &P : Opts.RPaths)
1781     B.template addLoadCommand<MachO::LC_RPATH>(P);
1782 
1783   auto HeaderContent = G.allocateBuffer(B.layout());
1784   B.write(HeaderContent);
1785 
1786   return G.createContentBlock(HeaderSection, HeaderContent, ExecutorAddr(), 8,
1787                               0);
1788 }
1789 
SimpleMachOHeaderMU(MachOPlatform & MOP,SymbolStringPtr HeaderStartSymbol,MachOPlatform::HeaderOptions Opts)1790 SimpleMachOHeaderMU::SimpleMachOHeaderMU(MachOPlatform &MOP,
1791                                          SymbolStringPtr HeaderStartSymbol,
1792                                          MachOPlatform::HeaderOptions Opts)
1793     : MaterializationUnit(
1794           createHeaderInterface(MOP, std::move(HeaderStartSymbol))),
1795       MOP(MOP), Opts(std::move(Opts)) {}
1796 
materialize(std::unique_ptr<MaterializationResponsibility> R)1797 void SimpleMachOHeaderMU::materialize(
1798     std::unique_ptr<MaterializationResponsibility> R) {
1799   auto G = createPlatformGraph(MOP, "<MachOHeaderMU>");
1800   addMachOHeader(R->getTargetJITDylib(), *G, R->getInitializerSymbol());
1801   MOP.getObjectLinkingLayer().emit(std::move(R), std::move(G));
1802 }
1803 
discard(const JITDylib & JD,const SymbolStringPtr & Sym)1804 void SimpleMachOHeaderMU::discard(const JITDylib &JD,
1805                                   const SymbolStringPtr &Sym) {}
1806 
addMachOHeader(JITDylib & JD,jitlink::LinkGraph & G,const SymbolStringPtr & InitializerSymbol)1807 void SimpleMachOHeaderMU::addMachOHeader(
1808     JITDylib &JD, jitlink::LinkGraph &G,
1809     const SymbolStringPtr &InitializerSymbol) {
1810   auto &HeaderSection = G.createSection("__header", MemProt::Read);
1811   auto &HeaderBlock = createHeaderBlock(JD, G, HeaderSection);
1812 
1813   // Init symbol is header-start symbol.
1814   G.addDefinedSymbol(HeaderBlock, 0, *InitializerSymbol, HeaderBlock.getSize(),
1815                      jitlink::Linkage::Strong, jitlink::Scope::Default, false,
1816                      true);
1817   for (auto &HS : AdditionalHeaderSymbols)
1818     G.addDefinedSymbol(HeaderBlock, HS.Offset, HS.Name, HeaderBlock.getSize(),
1819                        jitlink::Linkage::Strong, jitlink::Scope::Default, false,
1820                        true);
1821 }
1822 
1823 jitlink::Block &
createHeaderBlock(JITDylib & JD,jitlink::LinkGraph & G,jitlink::Section & HeaderSection)1824 SimpleMachOHeaderMU::createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
1825                                        jitlink::Section &HeaderSection) {
1826   switch (MOP.getExecutionSession().getTargetTriple().getArch()) {
1827   case Triple::aarch64:
1828   case Triple::x86_64:
1829     return ::createHeaderBlock<MachO64LE>(MOP, Opts, JD, G, HeaderSection);
1830   default:
1831     llvm_unreachable("Unsupported architecture");
1832   }
1833 }
1834 
createHeaderInterface(MachOPlatform & MOP,const SymbolStringPtr & HeaderStartSymbol)1835 MaterializationUnit::Interface SimpleMachOHeaderMU::createHeaderInterface(
1836     MachOPlatform &MOP, const SymbolStringPtr &HeaderStartSymbol) {
1837   SymbolFlagsMap HeaderSymbolFlags;
1838 
1839   HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported;
1840   for (auto &HS : AdditionalHeaderSymbols)
1841     HeaderSymbolFlags[MOP.getExecutionSession().intern(HS.Name)] =
1842         JITSymbolFlags::Exported;
1843 
1844   return MaterializationUnit::Interface(std::move(HeaderSymbolFlags),
1845                                         HeaderStartSymbol);
1846 }
1847 
getMachOHeaderInfoFromTriple(const Triple & TT)1848 MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT) {
1849   switch (TT.getArch()) {
1850   case Triple::aarch64:
1851     return {/* PageSize   = */ 16 * 1024,
1852             /* CPUType    = */ MachO::CPU_TYPE_ARM64,
1853             /* CPUSubType = */ MachO::CPU_SUBTYPE_ARM64_ALL};
1854   case Triple::x86_64:
1855     return {/* PageSize   = */ 4 * 1024,
1856             /* CPUType    = */ MachO::CPU_TYPE_X86_64,
1857             /* CPUSubType = */ MachO::CPU_SUBTYPE_X86_64_ALL};
1858   default:
1859     llvm_unreachable("Unrecognized architecture");
1860   }
1861 }
1862 
1863 } // End namespace orc.
1864 } // End namespace llvm.
1865