1 //===-- MachOPlatform.h - Utilities for executing MachO in Orc --*- C++ -*-===//
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 // Utilities for executing JIT'd MachO in Orc.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
14 #define LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
15 
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ExecutionEngine/Orc/Core.h"
18 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
19 #include "llvm/ExecutionEngine/Orc/LLVMSPSSerializers.h"
20 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
21 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
22 
23 #include <future>
24 #include <thread>
25 #include <vector>
26 
27 namespace llvm {
28 namespace orc {
29 
30 struct MachOPerObjectSectionsToRegister {
31   ExecutorAddressRange EHFrameSection;
32   ExecutorAddressRange ThreadDataSection;
33 };
34 
35 struct MachOJITDylibInitializers {
36   using SectionList = std::vector<ExecutorAddressRange>;
37 
MachOJITDylibInitializersMachOJITDylibInitializers38   MachOJITDylibInitializers(std::string Name,
39                             ExecutorAddress MachOHeaderAddress)
40       : Name(std::move(Name)),
41         MachOHeaderAddress(std::move(MachOHeaderAddress)) {}
42 
43   std::string Name;
44   ExecutorAddress MachOHeaderAddress;
45   ExecutorAddress ObjCImageInfoAddress;
46 
47   StringMap<SectionList> InitSections;
48 };
49 
50 class MachOJITDylibDeinitializers {};
51 
52 using MachOJITDylibInitializerSequence = std::vector<MachOJITDylibInitializers>;
53 
54 using MachOJITDylibDeinitializerSequence =
55     std::vector<MachOJITDylibDeinitializers>;
56 
57 /// Mediates between MachO initialization and ExecutionSession state.
58 class MachOPlatform : public Platform {
59 public:
60   /// Try to create a MachOPlatform instance, adding the ORC runtime to the
61   /// given JITDylib.
62   ///
63   /// The ORC runtime requires access to a number of symbols in libc++, and
64   /// requires access to symbols in libobjc, and libswiftCore to support
65   /// Objective-C and Swift code. It is up to the caller to ensure that the
66   /// requried symbols can be referenced by code added to PlatformJD. The
67   /// standard way to achieve this is to first attach dynamic library search
68   /// generators for either the given process, or for the specific required
69   /// libraries, to PlatformJD, then to create the platform instance:
70   ///
71   /// \code{.cpp}
72   ///   auto &PlatformJD = ES.createBareJITDylib("stdlib");
73   ///   PlatformJD.addGenerator(
74   ///     ExitOnErr(EPCDynamicLibrarySearchGenerator
75   ///                 ::GetForTargetProcess(EPC)));
76   ///   ES.setPlatform(
77   ///     ExitOnErr(MachOPlatform::Create(ES, ObjLayer, EPC, PlatformJD,
78   ///                                     "/path/to/orc/runtime")));
79   /// \endcode
80   ///
81   /// Alternatively, these symbols could be added to another JITDylib that
82   /// PlatformJD links against.
83   ///
84   /// Clients are also responsible for ensuring that any JIT'd code that
85   /// depends on runtime functions (including any code using TLV or static
86   /// destructors) can reference the runtime symbols. This is usually achieved
87   /// by linking any JITDylibs containing regular code against
88   /// PlatformJD.
89   ///
90   /// By default, MachOPlatform will add the set of aliases returned by the
91   /// standardPlatformAliases function. This includes both required aliases
92   /// (e.g. __cxa_atexit -> __orc_rt_macho_cxa_atexit for static destructor
93   /// support), and optional aliases that provide JIT versions of common
94   /// functions (e.g. dlopen -> __orc_rt_macho_jit_dlopen). Clients can
95   /// override these defaults by passing a non-None value for the
96   /// RuntimeAliases function, in which case the client is responsible for
97   /// setting up all aliases (including the required ones).
98   static Expected<std::unique_ptr<MachOPlatform>>
99   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
100          JITDylib &PlatformJD, const char *OrcRuntimePath,
101          Optional<SymbolAliasMap> RuntimeAliases = None);
102 
getExecutionSession()103   ExecutionSession &getExecutionSession() const { return ES; }
getObjectLinkingLayer()104   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
105 
106   Error setupJITDylib(JITDylib &JD) override;
107   Error notifyAdding(ResourceTracker &RT,
108                      const MaterializationUnit &MU) override;
109   Error notifyRemoving(ResourceTracker &RT) override;
110 
111   /// Returns an AliasMap containing the default aliases for the MachOPlatform.
112   /// This can be modified by clients when constructing the platform to add
113   /// or remove aliases.
114   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
115 
116   /// Returns the array of required CXX aliases.
117   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
118 
119   /// Returns the array of standard runtime utility aliases for MachO.
120   static ArrayRef<std::pair<const char *, const char *>>
121   standardRuntimeUtilityAliases();
122 
123   /// Returns true if the given section name is an initializer section.
124   static bool isInitializerSection(StringRef SegName, StringRef SectName);
125 
126 private:
127   // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO
128   // platform features including initializers, exceptions, TLV, and language
129   // runtime registration.
130   class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin {
131   public:
MachOPlatformPlugin(MachOPlatform & MP)132     MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {}
133 
134     void modifyPassConfig(MaterializationResponsibility &MR,
135                           jitlink::LinkGraph &G,
136                           jitlink::PassConfiguration &Config) override;
137 
138     SyntheticSymbolDependenciesMap
139     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
140 
141     // FIXME: We should be tentatively tracking scraped sections and discarding
142     // if the MR fails.
notifyFailed(MaterializationResponsibility & MR)143     Error notifyFailed(MaterializationResponsibility &MR) override {
144       return Error::success();
145     }
146 
notifyRemovingResources(ResourceKey K)147     Error notifyRemovingResources(ResourceKey K) override {
148       return Error::success();
149     }
150 
notifyTransferringResources(ResourceKey DstKey,ResourceKey SrcKey)151     void notifyTransferringResources(ResourceKey DstKey,
152                                      ResourceKey SrcKey) override {}
153 
154   private:
155     using InitSymbolDepMap =
156         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
157 
158     void addInitializerSupportPasses(MaterializationResponsibility &MR,
159                                      jitlink::PassConfiguration &Config);
160 
161     void addMachOHeaderSupportPasses(MaterializationResponsibility &MR,
162                                      jitlink::PassConfiguration &Config);
163 
164     void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
165                                   jitlink::PassConfiguration &Config);
166 
167     Error preserveInitSections(jitlink::LinkGraph &G,
168                                MaterializationResponsibility &MR);
169 
170     Error processObjCImageInfo(jitlink::LinkGraph &G,
171                                MaterializationResponsibility &MR);
172 
173     Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD);
174 
175     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
176 
177     std::mutex PluginMutex;
178     MachOPlatform &MP;
179     DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
180     InitSymbolDepMap InitSymbolDeps;
181   };
182 
183   using SendInitializerSequenceFn =
184       unique_function<void(Expected<MachOJITDylibInitializerSequence>)>;
185 
186   using SendDeinitializerSequenceFn =
187       unique_function<void(Expected<MachOJITDylibDeinitializerSequence>)>;
188 
189   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddress>)>;
190 
191   static bool supportedTarget(const Triple &TT);
192 
193   MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
194                 JITDylib &PlatformJD,
195                 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
196                 Error &Err);
197 
198   // Associate MachOPlatform JIT-side runtime support functions with handlers.
199   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
200 
201   void getInitializersBuildSequencePhase(SendInitializerSequenceFn SendResult,
202                                          JITDylib &JD,
203                                          std::vector<JITDylibSP> DFSLinkOrder);
204 
205   void getInitializersLookupPhase(SendInitializerSequenceFn SendResult,
206                                   JITDylib &JD);
207 
208   void rt_getInitializers(SendInitializerSequenceFn SendResult,
209                           StringRef JDName);
210 
211   void rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
212                             ExecutorAddress Handle);
213 
214   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddress Handle,
215                        StringRef SymbolName);
216 
217   // Records the addresses of runtime symbols used by the platform.
218   Error bootstrapMachORuntime(JITDylib &PlatformJD);
219 
220   Error registerInitInfo(JITDylib &JD, ExecutorAddress ObjCImageInfoAddr,
221                          ArrayRef<jitlink::Section *> InitSections);
222 
223   Error registerPerObjectSections(const MachOPerObjectSectionsToRegister &POSR);
224 
225   Expected<uint64_t> createPThreadKey();
226 
227   ExecutionSession &ES;
228   ObjectLinkingLayer &ObjLinkingLayer;
229 
230   SymbolStringPtr MachOHeaderStartSymbol;
231   std::atomic<bool> RuntimeBootstrapped{false};
232 
233   ExecutorAddress orc_rt_macho_platform_bootstrap;
234   ExecutorAddress orc_rt_macho_platform_shutdown;
235   ExecutorAddress orc_rt_macho_register_object_sections;
236   ExecutorAddress orc_rt_macho_create_pthread_key;
237 
238   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
239 
240   // InitSeqs gets its own mutex to avoid locking the whole session when
241   // aggregating data from the jitlink.
242   std::mutex PlatformMutex;
243   DenseMap<JITDylib *, MachOJITDylibInitializers> InitSeqs;
244   std::vector<MachOPerObjectSectionsToRegister> BootstrapPOSRs;
245 
246   DenseMap<JITTargetAddress, JITDylib *> HeaderAddrToJITDylib;
247   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
248 };
249 
250 namespace shared {
251 
252 using SPSMachOPerObjectSectionsToRegister =
253     SPSTuple<SPSExecutorAddressRange, SPSExecutorAddressRange>;
254 
255 template <>
256 class SPSSerializationTraits<SPSMachOPerObjectSectionsToRegister,
257                              MachOPerObjectSectionsToRegister> {
258 
259 public:
size(const MachOPerObjectSectionsToRegister & MOPOSR)260   static size_t size(const MachOPerObjectSectionsToRegister &MOPOSR) {
261     return SPSMachOPerObjectSectionsToRegister::AsArgList::size(
262         MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
263   }
264 
serialize(SPSOutputBuffer & OB,const MachOPerObjectSectionsToRegister & MOPOSR)265   static bool serialize(SPSOutputBuffer &OB,
266                         const MachOPerObjectSectionsToRegister &MOPOSR) {
267     return SPSMachOPerObjectSectionsToRegister::AsArgList::serialize(
268         OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
269   }
270 
deserialize(SPSInputBuffer & IB,MachOPerObjectSectionsToRegister & MOPOSR)271   static bool deserialize(SPSInputBuffer &IB,
272                           MachOPerObjectSectionsToRegister &MOPOSR) {
273     return SPSMachOPerObjectSectionsToRegister::AsArgList::deserialize(
274         IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
275   }
276 };
277 
278 using SPSNamedExecutorAddressRangeSequenceMap =
279     SPSSequence<SPSTuple<SPSString, SPSExecutorAddressRangeSequence>>;
280 
281 using SPSMachOJITDylibInitializers =
282     SPSTuple<SPSString, SPSExecutorAddress, SPSExecutorAddress,
283              SPSNamedExecutorAddressRangeSequenceMap>;
284 
285 using SPSMachOJITDylibInitializerSequence =
286     SPSSequence<SPSMachOJITDylibInitializers>;
287 
288 /// Serialization traits for MachOJITDylibInitializers.
289 template <>
290 class SPSSerializationTraits<SPSMachOJITDylibInitializers,
291                              MachOJITDylibInitializers> {
292 public:
size(const MachOJITDylibInitializers & MOJDIs)293   static size_t size(const MachOJITDylibInitializers &MOJDIs) {
294     return SPSMachOJITDylibInitializers::AsArgList::size(
295         MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
296         MOJDIs.InitSections);
297   }
298 
serialize(SPSOutputBuffer & OB,const MachOJITDylibInitializers & MOJDIs)299   static bool serialize(SPSOutputBuffer &OB,
300                         const MachOJITDylibInitializers &MOJDIs) {
301     return SPSMachOJITDylibInitializers::AsArgList::serialize(
302         OB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
303         MOJDIs.InitSections);
304   }
305 
deserialize(SPSInputBuffer & IB,MachOJITDylibInitializers & MOJDIs)306   static bool deserialize(SPSInputBuffer &IB,
307                           MachOJITDylibInitializers &MOJDIs) {
308     return SPSMachOJITDylibInitializers::AsArgList::deserialize(
309         IB, MOJDIs.Name, MOJDIs.MachOHeaderAddress, MOJDIs.ObjCImageInfoAddress,
310         MOJDIs.InitSections);
311   }
312 };
313 
314 using SPSMachOJITDylibDeinitializers = SPSEmpty;
315 
316 using SPSMachOJITDylibDeinitializerSequence =
317     SPSSequence<SPSMachOJITDylibDeinitializers>;
318 
319 template <>
320 class SPSSerializationTraits<SPSMachOJITDylibDeinitializers,
321                              MachOJITDylibDeinitializers> {
322 public:
size(const MachOJITDylibDeinitializers & MOJDDs)323   static size_t size(const MachOJITDylibDeinitializers &MOJDDs) { return 0; }
324 
serialize(SPSOutputBuffer & OB,const MachOJITDylibDeinitializers & MOJDDs)325   static bool serialize(SPSOutputBuffer &OB,
326                         const MachOJITDylibDeinitializers &MOJDDs) {
327     return true;
328   }
329 
deserialize(SPSInputBuffer & IB,MachOJITDylibDeinitializers & MOJDDs)330   static bool deserialize(SPSInputBuffer &IB,
331                           MachOJITDylibDeinitializers &MOJDDs) {
332     MOJDDs = MachOJITDylibDeinitializers();
333     return true;
334   }
335 };
336 
337 } // end namespace shared
338 } // end namespace orc
339 } // end namespace llvm
340 
341 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
342