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 /// Mediates between MachO initialization and ExecutionSession state.
30 class MachOPlatform : public Platform {
31 public:
32   // Used internally by MachOPlatform, but made public to enable serialization.
33   struct MachOJITDylibDepInfo {
34     bool Sealed = false;
35     std::vector<ExecutorAddr> DepHeaders;
36   };
37 
38   // Used internally by MachOPlatform, but made public to enable serialization.
39   using MachOJITDylibDepInfoMap =
40       std::vector<std::pair<ExecutorAddr, MachOJITDylibDepInfo>>;
41 
42   /// Try to create a MachOPlatform instance, adding the ORC runtime to the
43   /// given JITDylib.
44   ///
45   /// The ORC runtime requires access to a number of symbols in libc++, and
46   /// requires access to symbols in libobjc, and libswiftCore to support
47   /// Objective-C and Swift code. It is up to the caller to ensure that the
48   /// requried symbols can be referenced by code added to PlatformJD. The
49   /// standard way to achieve this is to first attach dynamic library search
50   /// generators for either the given process, or for the specific required
51   /// libraries, to PlatformJD, then to create the platform instance:
52   ///
53   /// \code{.cpp}
54   ///   auto &PlatformJD = ES.createBareJITDylib("stdlib");
55   ///   PlatformJD.addGenerator(
56   ///     ExitOnErr(EPCDynamicLibrarySearchGenerator
57   ///                 ::GetForTargetProcess(EPC)));
58   ///   ES.setPlatform(
59   ///     ExitOnErr(MachOPlatform::Create(ES, ObjLayer, EPC, PlatformJD,
60   ///                                     "/path/to/orc/runtime")));
61   /// \endcode
62   ///
63   /// Alternatively, these symbols could be added to another JITDylib that
64   /// PlatformJD links against.
65   ///
66   /// Clients are also responsible for ensuring that any JIT'd code that
67   /// depends on runtime functions (including any code using TLV or static
68   /// destructors) can reference the runtime symbols. This is usually achieved
69   /// by linking any JITDylibs containing regular code against
70   /// PlatformJD.
71   ///
72   /// By default, MachOPlatform will add the set of aliases returned by the
73   /// standardPlatformAliases function. This includes both required aliases
74   /// (e.g. __cxa_atexit -> __orc_rt_macho_cxa_atexit for static destructor
75   /// support), and optional aliases that provide JIT versions of common
76   /// functions (e.g. dlopen -> __orc_rt_macho_jit_dlopen). Clients can
77   /// override these defaults by passing a non-None value for the
78   /// RuntimeAliases function, in which case the client is responsible for
79   /// setting up all aliases (including the required ones).
80   static Expected<std::unique_ptr<MachOPlatform>>
81   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
82          JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
83          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
84 
85   /// Construct using a path to the ORC runtime.
86   static Expected<std::unique_ptr<MachOPlatform>>
87   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
88          JITDylib &PlatformJD, const char *OrcRuntimePath,
89          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
90 
91   ExecutionSession &getExecutionSession() const { return ES; }
92   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
93 
94   Error setupJITDylib(JITDylib &JD) override;
95   Error teardownJITDylib(JITDylib &JD) override;
96   Error notifyAdding(ResourceTracker &RT,
97                      const MaterializationUnit &MU) override;
98   Error notifyRemoving(ResourceTracker &RT) override;
99 
100   /// Returns an AliasMap containing the default aliases for the MachOPlatform.
101   /// This can be modified by clients when constructing the platform to add
102   /// or remove aliases.
103   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
104 
105   /// Returns the array of required CXX aliases.
106   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
107 
108   /// Returns the array of standard runtime utility aliases for MachO.
109   static ArrayRef<std::pair<const char *, const char *>>
110   standardRuntimeUtilityAliases();
111 
112 private:
113   // Data needed for bootstrap only.
114   struct BootstrapInfo {
115     std::mutex Mutex;
116     std::condition_variable CV;
117     size_t ActiveGraphs = 0;
118     shared::AllocActions DeferredAAs;
119     ExecutorAddr MachOHeaderAddr;
120   };
121 
122   // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO
123   // platform features including initializers, exceptions, TLV, and language
124   // runtime registration.
125   class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin {
126   public:
127     MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {}
128 
129     void modifyPassConfig(MaterializationResponsibility &MR,
130                           jitlink::LinkGraph &G,
131                           jitlink::PassConfiguration &Config) override;
132 
133     SyntheticSymbolDependenciesMap
134     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
135 
136     // FIXME: We should be tentatively tracking scraped sections and discarding
137     // if the MR fails.
138     Error notifyFailed(MaterializationResponsibility &MR) override {
139       return Error::success();
140     }
141 
142     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
143       return Error::success();
144     }
145 
146     void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
147                                      ResourceKey SrcKey) override {}
148 
149   private:
150     using InitSymbolDepMap =
151         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
152 
153     struct UnwindSections {
154       SmallVector<ExecutorAddrRange> CodeRanges;
155       ExecutorAddrRange DwarfSection;
156       ExecutorAddrRange CompactUnwindSection;
157     };
158 
159     struct ObjCImageInfo {
160       uint32_t Version = 0;
161       uint32_t Flags = 0;
162     };
163 
164     Error bootstrapPipelineStart(jitlink::LinkGraph &G);
165     Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
166     Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
167 
168     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
169                                         MaterializationResponsibility &MR);
170 
171     Error preserveImportantSections(jitlink::LinkGraph &G,
172                                     MaterializationResponsibility &MR);
173 
174     Error processObjCImageInfo(jitlink::LinkGraph &G,
175                                MaterializationResponsibility &MR);
176 
177     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
178 
179     std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G);
180 
181     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD,
182                                          bool InBootstrapPhase);
183 
184     Error createObjCRuntimeObject(jitlink::LinkGraph &G);
185     Error populateObjCRuntimeObject(jitlink::LinkGraph &G,
186                                     MaterializationResponsibility &MR);
187 
188     std::mutex PluginMutex;
189     MachOPlatform &MP;
190 
191     // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when
192     // JITDylibs are removed.
193     DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos;
194     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
195     InitSymbolDepMap InitSymbolDeps;
196   };
197 
198   using GetJITDylibHeaderSendResultFn =
199       unique_function<void(Expected<ExecutorAddr>)>;
200   using GetJITDylibNameSendResultFn =
201       unique_function<void(Expected<StringRef>)>;
202   using PushInitializersSendResultFn =
203       unique_function<void(Expected<MachOJITDylibDepInfoMap>)>;
204   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
205 
206   static bool supportedTarget(const Triple &TT);
207 
208   MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
209                 JITDylib &PlatformJD,
210                 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
211                 Error &Err);
212 
213   // Associate MachOPlatform JIT-side runtime support functions with handlers.
214   Error associateRuntimeSupportFunctions();
215 
216   // Implements rt_pushInitializers by making repeat async lookups for
217   // initializer symbols (each lookup may spawn more initializer symbols if
218   // it pulls in new materializers, e.g. from objects in a static library).
219   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
220                             JITDylibSP JD);
221 
222   // Handle requests from the ORC runtime to push MachO initializer info.
223   void rt_pushInitializers(PushInitializersSendResultFn SendResult,
224                            ExecutorAddr JDHeaderAddr);
225 
226   // Handle requests for symbol addresses from the ORC runtime.
227   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
228                        StringRef SymbolName);
229 
230   // Call the ORC runtime to create a pthread key.
231   Expected<uint64_t> createPThreadKey();
232 
233   ExecutionSession &ES;
234   JITDylib &PlatformJD;
235   ObjectLinkingLayer &ObjLinkingLayer;
236 
237   SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle");
238 
239   struct RuntimeFunction {
240     RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {}
241     SymbolStringPtr Name;
242     ExecutorAddr Addr;
243   };
244 
245   RuntimeFunction PlatformBootstrap{
246       ES.intern("___orc_rt_macho_platform_bootstrap")};
247   RuntimeFunction PlatformShutdown{
248       ES.intern("___orc_rt_macho_platform_shutdown")};
249   RuntimeFunction RegisterEHFrameSection{
250       ES.intern("___orc_rt_macho_register_ehframe_section")};
251   RuntimeFunction DeregisterEHFrameSection{
252       ES.intern("___orc_rt_macho_deregister_ehframe_section")};
253   RuntimeFunction RegisterJITDylib{
254       ES.intern("___orc_rt_macho_register_jitdylib")};
255   RuntimeFunction DeregisterJITDylib{
256       ES.intern("___orc_rt_macho_deregister_jitdylib")};
257   RuntimeFunction RegisterObjectPlatformSections{
258       ES.intern("___orc_rt_macho_register_object_platform_sections")};
259   RuntimeFunction DeregisterObjectPlatformSections{
260       ES.intern("___orc_rt_macho_deregister_object_platform_sections")};
261   RuntimeFunction CreatePThreadKey{
262       ES.intern("___orc_rt_macho_create_pthread_key")};
263   RuntimeFunction RegisterObjCRuntimeObject{
264       ES.intern("___orc_rt_macho_register_objc_runtime_object")};
265   RuntimeFunction DeregisterObjCRuntimeObject{
266       ES.intern("___orc_rt_macho_deregister_objc_runtime_object")};
267 
268   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
269 
270   std::mutex PlatformMutex;
271   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr;
272   DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
273   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
274 
275   std::atomic<BootstrapInfo *> Bootstrap;
276 };
277 
278 namespace shared {
279 
280 using SPSNamedExecutorAddrRangeSequence =
281     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
282 
283 } // end namespace shared
284 } // end namespace orc
285 } // end namespace llvm
286 
287 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
288