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