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, const char *OrcRuntimePath,
83          Optional<SymbolAliasMap> RuntimeAliases = None);
84 
85   ExecutionSession &getExecutionSession() const { return ES; }
86   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
87 
88   Error setupJITDylib(JITDylib &JD) override;
89   Error teardownJITDylib(JITDylib &JD) override;
90   Error notifyAdding(ResourceTracker &RT,
91                      const MaterializationUnit &MU) override;
92   Error notifyRemoving(ResourceTracker &RT) override;
93 
94   /// Returns an AliasMap containing the default aliases for the MachOPlatform.
95   /// This can be modified by clients when constructing the platform to add
96   /// or remove aliases.
97   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
98 
99   /// Returns the array of required CXX aliases.
100   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
101 
102   /// Returns the array of standard runtime utility aliases for MachO.
103   static ArrayRef<std::pair<const char *, const char *>>
104   standardRuntimeUtilityAliases();
105 
106   /// Returns true if the given section name is an initializer section.
107   static bool isInitializerSection(StringRef SegName, StringRef SectName);
108 
109 private:
110   // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO
111   // platform features including initializers, exceptions, TLV, and language
112   // runtime registration.
113   class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin {
114   public:
115     MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {}
116 
117     void modifyPassConfig(MaterializationResponsibility &MR,
118                           jitlink::LinkGraph &G,
119                           jitlink::PassConfiguration &Config) override;
120 
121     SyntheticSymbolDependenciesMap
122     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
123 
124     // FIXME: We should be tentatively tracking scraped sections and discarding
125     // if the MR fails.
126     Error notifyFailed(MaterializationResponsibility &MR) override {
127       return Error::success();
128     }
129 
130     Error notifyRemovingResources(ResourceKey K) override {
131       return Error::success();
132     }
133 
134     void notifyTransferringResources(ResourceKey DstKey,
135                                      ResourceKey SrcKey) override {}
136 
137   private:
138     using InitSymbolDepMap =
139         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
140 
141     void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
142                                   jitlink::PassConfiguration &Config);
143 
144     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
145                                         MaterializationResponsibility &MR);
146 
147     Error preserveInitSections(jitlink::LinkGraph &G,
148                                MaterializationResponsibility &MR);
149 
150     Error processObjCImageInfo(jitlink::LinkGraph &G,
151                                MaterializationResponsibility &MR);
152 
153     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
154 
155     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD);
156 
157     Error registerEHSectionsPhase1(jitlink::LinkGraph &G);
158 
159     std::mutex PluginMutex;
160     MachOPlatform &MP;
161 
162     // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when
163     // JITDylibs are removed.
164     DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
165     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
166     InitSymbolDepMap InitSymbolDeps;
167   };
168 
169   using GetJITDylibHeaderSendResultFn =
170       unique_function<void(Expected<ExecutorAddr>)>;
171   using GetJITDylibNameSendResultFn =
172       unique_function<void(Expected<StringRef>)>;
173   using PushInitializersSendResultFn =
174       unique_function<void(Expected<MachOJITDylibDepInfoMap>)>;
175   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
176 
177   static bool supportedTarget(const Triple &TT);
178 
179   MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
180                 JITDylib &PlatformJD,
181                 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
182                 Error &Err);
183 
184   // Associate MachOPlatform JIT-side runtime support functions with handlers.
185   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
186 
187   // Implements rt_pushInitializers by making repeat async lookups for
188   // initializer symbols (each lookup may spawn more initializer symbols if
189   // it pulls in new materializers, e.g. from objects in a static library).
190   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
191                             JITDylibSP JD);
192 
193   // Handle requests from the ORC runtime to push MachO initializer info.
194   void rt_pushInitializers(PushInitializersSendResultFn SendResult,
195                            ExecutorAddr JDHeaderAddr);
196 
197   // Handle requests for symbol addresses from the ORC runtime.
198   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
199                        StringRef SymbolName);
200 
201   // Records the addresses of runtime symbols used by the platform.
202   Error bootstrapMachORuntime(JITDylib &PlatformJD);
203 
204   // Call the ORC runtime to create a pthread key.
205   Expected<uint64_t> createPThreadKey();
206 
207   enum PlatformState { BootstrapPhase1, BootstrapPhase2, Initialized };
208 
209   ExecutionSession &ES;
210   ObjectLinkingLayer &ObjLinkingLayer;
211 
212   SymbolStringPtr MachOHeaderStartSymbol;
213   std::atomic<PlatformState> State{BootstrapPhase1};
214 
215   ExecutorAddr orc_rt_macho_platform_bootstrap;
216   ExecutorAddr orc_rt_macho_platform_shutdown;
217   ExecutorAddr orc_rt_macho_register_ehframe_section;
218   ExecutorAddr orc_rt_macho_deregister_ehframe_section;
219   ExecutorAddr orc_rt_macho_register_jitdylib;
220   ExecutorAddr orc_rt_macho_deregister_jitdylib;
221   ExecutorAddr orc_rt_macho_register_object_platform_sections;
222   ExecutorAddr orc_rt_macho_deregister_object_platform_sections;
223   ExecutorAddr orc_rt_macho_create_pthread_key;
224 
225   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
226 
227   std::mutex PlatformMutex;
228   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr;
229   DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
230   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
231 };
232 
233 namespace shared {
234 
235 using SPSNamedExecutorAddrRangeSequence =
236     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
237 
238 } // end namespace shared
239 } // end namespace orc
240 } // end namespace llvm
241 
242 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
243