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          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
84 
getExecutionSession()85   ExecutionSession &getExecutionSession() const { return ES; }
getObjectLinkingLayer()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   // Data needed for bootstrap only.
111   struct BootstrapInfo {
112     std::mutex Mutex;
113     std::condition_variable CV;
114     size_t ActiveGraphs = 0;
115     shared::AllocActions DeferredAAs;
116     ExecutorAddr MachOHeaderAddr;
117   };
118 
119   // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO
120   // platform features including initializers, exceptions, TLV, and language
121   // runtime registration.
122   class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin {
123   public:
MachOPlatformPlugin(MachOPlatform & MP)124     MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {}
125 
126     void modifyPassConfig(MaterializationResponsibility &MR,
127                           jitlink::LinkGraph &G,
128                           jitlink::PassConfiguration &Config) override;
129 
130     SyntheticSymbolDependenciesMap
131     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
132 
133     // FIXME: We should be tentatively tracking scraped sections and discarding
134     // if the MR fails.
notifyFailed(MaterializationResponsibility & MR)135     Error notifyFailed(MaterializationResponsibility &MR) override {
136       return Error::success();
137     }
138 
notifyRemovingResources(JITDylib & JD,ResourceKey K)139     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
140       return Error::success();
141     }
142 
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)143     void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
144                                      ResourceKey SrcKey) override {}
145 
146   private:
147     using InitSymbolDepMap =
148         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
149 
150     struct UnwindSections {
151       SmallVector<ExecutorAddrRange> CodeRanges;
152       ExecutorAddrRange DwarfSection;
153       ExecutorAddrRange CompactUnwindSection;
154     };
155 
156     Error bootstrapPipelineStart(jitlink::LinkGraph &G);
157     Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
158     Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
159 
160     Error recordRuntimeRegistrationFunctions(jitlink::LinkGraph &G);
161 
162     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
163                                         MaterializationResponsibility &MR);
164 
165     Error preserveInitSections(jitlink::LinkGraph &G,
166                                MaterializationResponsibility &MR);
167 
168     Error processObjCImageInfo(jitlink::LinkGraph &G,
169                                MaterializationResponsibility &MR);
170 
171     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
172 
173     std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G);
174 
175     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD,
176                                          bool InBootstrapPhase);
177 
178     std::mutex PluginMutex;
179     MachOPlatform &MP;
180 
181     // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when
182     // JITDylibs are removed.
183     DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
184     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
185     InitSymbolDepMap InitSymbolDeps;
186   };
187 
188   using GetJITDylibHeaderSendResultFn =
189       unique_function<void(Expected<ExecutorAddr>)>;
190   using GetJITDylibNameSendResultFn =
191       unique_function<void(Expected<StringRef>)>;
192   using PushInitializersSendResultFn =
193       unique_function<void(Expected<MachOJITDylibDepInfoMap>)>;
194   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
195 
196   static bool supportedTarget(const Triple &TT);
197 
198   MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
199                 JITDylib &PlatformJD,
200                 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
201                 Error &Err);
202 
203   // Associate MachOPlatform JIT-side runtime support functions with handlers.
204   Error associateRuntimeSupportFunctions();
205 
206   // Implements rt_pushInitializers by making repeat async lookups for
207   // initializer symbols (each lookup may spawn more initializer symbols if
208   // it pulls in new materializers, e.g. from objects in a static library).
209   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
210                             JITDylibSP JD);
211 
212   // Handle requests from the ORC runtime to push MachO initializer info.
213   void rt_pushInitializers(PushInitializersSendResultFn SendResult,
214                            ExecutorAddr JDHeaderAddr);
215 
216   // Handle requests for symbol addresses from the ORC runtime.
217   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
218                        StringRef SymbolName);
219 
220   // Call the ORC runtime to create a pthread key.
221   Expected<uint64_t> createPThreadKey();
222 
223   ExecutionSession &ES;
224   JITDylib &PlatformJD;
225   ObjectLinkingLayer &ObjLinkingLayer;
226 
227   SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle");
228 
229   struct RuntimeFunction {
RuntimeFunctionRuntimeFunction230     RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {}
231     SymbolStringPtr Name;
232     ExecutorAddr Addr;
233   };
234 
235   RuntimeFunction PlatformBootstrap{
236       ES.intern("___orc_rt_macho_platform_bootstrap")};
237   RuntimeFunction PlatformShutdown{
238       ES.intern("___orc_rt_macho_platform_shutdown")};
239   RuntimeFunction RegisterEHFrameSection{
240       ES.intern("___orc_rt_macho_register_ehframe_section")};
241   RuntimeFunction DeregisterEHFrameSection{
242       ES.intern("___orc_rt_macho_deregister_ehframe_section")};
243   RuntimeFunction RegisterJITDylib{
244       ES.intern("___orc_rt_macho_register_jitdylib")};
245   RuntimeFunction DeregisterJITDylib{
246       ES.intern("___orc_rt_macho_deregister_jitdylib")};
247   RuntimeFunction RegisterObjectPlatformSections{
248       ES.intern("___orc_rt_macho_register_object_platform_sections")};
249   RuntimeFunction DeregisterObjectPlatformSections{
250       ES.intern("___orc_rt_macho_deregister_object_platform_sections")};
251   RuntimeFunction CreatePThreadKey{
252       ES.intern("___orc_rt_macho_create_pthread_key")};
253 
254   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
255 
256   std::mutex PlatformMutex;
257   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr;
258   DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
259   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
260 
261   std::atomic<BootstrapInfo *> Bootstrap;
262 };
263 
264 namespace shared {
265 
266 using SPSNamedExecutorAddrRangeSequence =
267     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
268 
269 } // end namespace shared
270 } // end namespace orc
271 } // end namespace llvm
272 
273 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
274