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> ; |
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 | // Used internally by MachOPlatform, but made public to enable serialization. |
43 | enum class MachOExecutorSymbolFlags : uint8_t { |
44 | None = 0, |
45 | Weak = 1U << 0, |
46 | Callable = 1U << 1, |
47 | LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Callable) |
48 | }; |
49 | |
50 | /// Configuration for the mach-o header of a JITDylib. Specify common load |
51 | /// commands that should be added to the header. |
52 | struct { |
53 | /// A dylib for use with a dylib command (e.g. LC_ID_DYLIB, LC_LOAD_DYLIB). |
54 | struct { |
55 | std::string ; |
56 | uint32_t ; |
57 | uint32_t ; |
58 | uint32_t ; |
59 | }; |
60 | |
61 | /// Override for LC_IC_DYLIB. If this is nullopt, {JD.getName(), 0, 0, 0} |
62 | /// will be used. |
63 | std::optional<Dylib> ; |
64 | /// List of LC_LOAD_DYLIBs. |
65 | std::vector<Dylib> ; |
66 | /// List of LC_RPATHs. |
67 | std::vector<std::string> ; |
68 | |
69 | () = default; |
70 | (Dylib D) : IDDylib(std::move(D)) {} |
71 | }; |
72 | |
73 | /// Used by setupJITDylib to create MachO header MaterializationUnits for |
74 | /// JITDylibs. |
75 | using = |
76 | unique_function<std::unique_ptr<MaterializationUnit>(MachOPlatform &MOP, |
77 | HeaderOptions Opts)>; |
78 | |
79 | /// Simple MachO header graph builder. |
80 | static inline std::unique_ptr<MaterializationUnit> |
81 | buildSimpleMachOHeaderMU(MachOPlatform &MOP, HeaderOptions Opts); |
82 | |
83 | /// Try to create a MachOPlatform instance, adding the ORC runtime to the |
84 | /// given JITDylib. |
85 | /// |
86 | /// The ORC runtime requires access to a number of symbols in libc++, and |
87 | /// requires access to symbols in libobjc, and libswiftCore to support |
88 | /// Objective-C and Swift code. It is up to the caller to ensure that the |
89 | /// required symbols can be referenced by code added to PlatformJD. The |
90 | /// standard way to achieve this is to first attach dynamic library search |
91 | /// generators for either the given process, or for the specific required |
92 | /// libraries, to PlatformJD, then to create the platform instance: |
93 | /// |
94 | /// \code{.cpp} |
95 | /// auto &PlatformJD = ES.createBareJITDylib("stdlib"); |
96 | /// PlatformJD.addGenerator( |
97 | /// ExitOnErr(EPCDynamicLibrarySearchGenerator |
98 | /// ::GetForTargetProcess(EPC))); |
99 | /// ES.setPlatform( |
100 | /// ExitOnErr(MachOPlatform::Create(ES, ObjLayer, EPC, PlatformJD, |
101 | /// "/path/to/orc/runtime"))); |
102 | /// \endcode |
103 | /// |
104 | /// Alternatively, these symbols could be added to another JITDylib that |
105 | /// PlatformJD links against. |
106 | /// |
107 | /// Clients are also responsible for ensuring that any JIT'd code that |
108 | /// depends on runtime functions (including any code using TLV or static |
109 | /// destructors) can reference the runtime symbols. This is usually achieved |
110 | /// by linking any JITDylibs containing regular code against |
111 | /// PlatformJD. |
112 | /// |
113 | /// By default, MachOPlatform will add the set of aliases returned by the |
114 | /// standardPlatformAliases function. This includes both required aliases |
115 | /// (e.g. __cxa_atexit -> __orc_rt_macho_cxa_atexit for static destructor |
116 | /// support), and optional aliases that provide JIT versions of common |
117 | /// functions (e.g. dlopen -> __orc_rt_macho_jit_dlopen). Clients can |
118 | /// override these defaults by passing a non-None value for the |
119 | /// RuntimeAliases function, in which case the client is responsible for |
120 | /// setting up all aliases (including the required ones). |
121 | static Expected<std::unique_ptr<MachOPlatform>> |
122 | Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, |
123 | JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime, |
124 | HeaderOptions PlatformJDOpts = {}, |
125 | MachOHeaderMUBuilder = buildSimpleMachOHeaderMU, |
126 | std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); |
127 | |
128 | /// Construct using a path to the ORC runtime. |
129 | static Expected<std::unique_ptr<MachOPlatform>> |
130 | (ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, |
131 | JITDylib &PlatformJD, const char *OrcRuntimePath, |
132 | HeaderOptions PlatformJDOpts = {}, |
133 | MachOHeaderMUBuilder = buildSimpleMachOHeaderMU, |
134 | std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt); |
135 | |
136 | ExecutionSession &getExecutionSession() const { return ES; } |
137 | ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; } |
138 | |
139 | NonOwningSymbolStringPtr () const { |
140 | return NonOwningSymbolStringPtr(MachOHeaderStartSymbol); |
141 | } |
142 | |
143 | Error setupJITDylib(JITDylib &JD) override; |
144 | |
145 | /// Install any platform-specific symbols (e.g. `__dso_handle`) and create a |
146 | /// mach-o header based on the given options. |
147 | Error (JITDylib &JD, HeaderOptions Opts); |
148 | |
149 | Error teardownJITDylib(JITDylib &JD) override; |
150 | Error notifyAdding(ResourceTracker &RT, |
151 | const MaterializationUnit &MU) override; |
152 | Error notifyRemoving(ResourceTracker &RT) override; |
153 | |
154 | /// Returns an AliasMap containing the default aliases for the MachOPlatform. |
155 | /// This can be modified by clients when constructing the platform to add |
156 | /// or remove aliases. |
157 | static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES); |
158 | |
159 | /// Returns the array of required CXX aliases. |
160 | static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases(); |
161 | |
162 | /// Returns the array of standard runtime utility aliases for MachO. |
163 | static ArrayRef<std::pair<const char *, const char *>> |
164 | standardRuntimeUtilityAliases(); |
165 | |
166 | private: |
167 | using SymbolTableVector = SmallVector< |
168 | std::tuple<ExecutorAddr, ExecutorAddr, MachOExecutorSymbolFlags>>; |
169 | |
170 | // Data needed for bootstrap only. |
171 | struct BootstrapInfo { |
172 | std::mutex Mutex; |
173 | std::condition_variable CV; |
174 | size_t ActiveGraphs = 0; |
175 | shared::AllocActions DeferredAAs; |
176 | ExecutorAddr ; |
177 | SymbolTableVector SymTab; |
178 | }; |
179 | |
180 | // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO |
181 | // platform features including initializers, exceptions, TLV, and language |
182 | // runtime registration. |
183 | class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin { |
184 | public: |
185 | MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {} |
186 | |
187 | void modifyPassConfig(MaterializationResponsibility &MR, |
188 | jitlink::LinkGraph &G, |
189 | jitlink::PassConfiguration &Config) override; |
190 | |
191 | SyntheticSymbolDependenciesMap |
192 | getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override; |
193 | |
194 | // FIXME: We should be tentatively tracking scraped sections and discarding |
195 | // if the MR fails. |
196 | Error notifyFailed(MaterializationResponsibility &MR) override { |
197 | return Error::success(); |
198 | } |
199 | |
200 | Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { |
201 | return Error::success(); |
202 | } |
203 | |
204 | void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, |
205 | ResourceKey SrcKey) override {} |
206 | |
207 | private: |
208 | using InitSymbolDepMap = |
209 | DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>; |
210 | |
211 | struct UnwindSections { |
212 | SmallVector<ExecutorAddrRange> CodeRanges; |
213 | ExecutorAddrRange DwarfSection; |
214 | ExecutorAddrRange CompactUnwindSection; |
215 | }; |
216 | |
217 | struct ObjCImageInfo { |
218 | uint32_t Version = 0; |
219 | uint32_t Flags = 0; |
220 | /// Whether this image info can no longer be mutated, as it may have been |
221 | /// registered with the objc runtime. |
222 | bool Finalized = false; |
223 | }; |
224 | |
225 | struct SymbolTablePair { |
226 | jitlink::Symbol *OriginalSym = nullptr; |
227 | jitlink::Symbol *NameSym = nullptr; |
228 | }; |
229 | using JITSymTabVector = SmallVector<SymbolTablePair>; |
230 | |
231 | Error bootstrapPipelineStart(jitlink::LinkGraph &G); |
232 | Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G); |
233 | Error bootstrapPipelineEnd(jitlink::LinkGraph &G); |
234 | |
235 | Error (jitlink::LinkGraph &G, |
236 | MaterializationResponsibility &MR); |
237 | |
238 | Error preserveImportantSections(jitlink::LinkGraph &G, |
239 | MaterializationResponsibility &MR); |
240 | |
241 | Error processObjCImageInfo(jitlink::LinkGraph &G, |
242 | MaterializationResponsibility &MR); |
243 | Error mergeImageInfoFlags(jitlink::LinkGraph &G, |
244 | MaterializationResponsibility &MR, |
245 | ObjCImageInfo &Info, uint32_t NewFlags); |
246 | |
247 | Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD); |
248 | |
249 | std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G); |
250 | Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD, |
251 | bool InBootstrapPhase); |
252 | |
253 | Error createObjCRuntimeObject(jitlink::LinkGraph &G); |
254 | Error populateObjCRuntimeObject(jitlink::LinkGraph &G, |
255 | MaterializationResponsibility &MR); |
256 | |
257 | Error prepareSymbolTableRegistration(jitlink::LinkGraph &G, |
258 | JITSymTabVector &JITSymTabInfo); |
259 | Error addSymbolTableRegistration(jitlink::LinkGraph &G, |
260 | MaterializationResponsibility &MR, |
261 | JITSymTabVector &JITSymTabInfo, |
262 | bool InBootstrapPhase); |
263 | |
264 | std::mutex PluginMutex; |
265 | MachOPlatform &MP; |
266 | |
267 | // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when |
268 | // JITDylibs are removed. |
269 | DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos; |
270 | DenseMap<JITDylib *, ExecutorAddr> ; |
271 | InitSymbolDepMap InitSymbolDeps; |
272 | }; |
273 | |
274 | using = |
275 | unique_function<void(Expected<ExecutorAddr>)>; |
276 | using GetJITDylibNameSendResultFn = |
277 | unique_function<void(Expected<StringRef>)>; |
278 | using = |
279 | unique_function<void(Expected<MachOJITDylibDepInfoMap>)>; |
280 | using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>; |
281 | using PushSymbolsInSendResultFn = unique_function<void(Error)>; |
282 | |
283 | static bool supportedTarget(const Triple &TT); |
284 | |
285 | static jitlink::Edge::Kind getPointerEdgeKind(jitlink::LinkGraph &G); |
286 | |
287 | static MachOExecutorSymbolFlags flagsForSymbol(jitlink::Symbol &Sym); |
288 | |
289 | MachOPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, |
290 | JITDylib &PlatformJD, |
291 | std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, |
292 | HeaderOptions PlatformJDOpts, |
293 | MachOHeaderMUBuilder , Error &Err); |
294 | |
295 | // Associate MachOPlatform JIT-side runtime support functions with handlers. |
296 | Error associateRuntimeSupportFunctions(); |
297 | |
298 | // Implements rt_pushInitializers by making repeat async lookups for |
299 | // initializer symbols (each lookup may spawn more initializer symbols if |
300 | // it pulls in new materializers, e.g. from objects in a static library). |
301 | void pushInitializersLoop(PushInitializersSendResultFn SendResult, |
302 | JITDylibSP JD); |
303 | |
304 | // Handle requests from the ORC runtime to push MachO initializer info. |
305 | void rt_pushInitializers(PushInitializersSendResultFn SendResult, |
306 | ExecutorAddr ); |
307 | |
308 | // Request that that the given symbols be materialized. The bool element of |
309 | // each pair indicates whether the symbol must be initialized, or whether it |
310 | // is optional. If any required symbol is not found then the pushSymbols |
311 | // function will return an error. |
312 | void rt_pushSymbols(PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle, |
313 | const std::vector<std::pair<StringRef, bool>> &Symbols); |
314 | |
315 | // Call the ORC runtime to create a pthread key. |
316 | Expected<uint64_t> createPThreadKey(); |
317 | |
318 | ExecutionSession &ES; |
319 | JITDylib &PlatformJD; |
320 | ObjectLinkingLayer &ObjLinkingLayer; |
321 | MachOHeaderMUBuilder ; |
322 | |
323 | SymbolStringPtr = ES.intern(SymName: "___dso_handle" ); |
324 | |
325 | struct RuntimeFunction { |
326 | RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {} |
327 | SymbolStringPtr Name; |
328 | ExecutorAddr Addr; |
329 | }; |
330 | |
331 | RuntimeFunction PlatformBootstrap{ |
332 | ES.intern(SymName: "___orc_rt_macho_platform_bootstrap" )}; |
333 | RuntimeFunction PlatformShutdown{ |
334 | ES.intern(SymName: "___orc_rt_macho_platform_shutdown" )}; |
335 | RuntimeFunction RegisterEHFrameSection{ |
336 | ES.intern(SymName: "___orc_rt_macho_register_ehframe_section" )}; |
337 | RuntimeFunction DeregisterEHFrameSection{ |
338 | ES.intern(SymName: "___orc_rt_macho_deregister_ehframe_section" )}; |
339 | RuntimeFunction RegisterJITDylib{ |
340 | ES.intern(SymName: "___orc_rt_macho_register_jitdylib" )}; |
341 | RuntimeFunction DeregisterJITDylib{ |
342 | ES.intern(SymName: "___orc_rt_macho_deregister_jitdylib" )}; |
343 | RuntimeFunction RegisterObjectSymbolTable{ |
344 | ES.intern(SymName: "___orc_rt_macho_register_object_symbol_table" )}; |
345 | RuntimeFunction DeregisterObjectSymbolTable{ |
346 | ES.intern(SymName: "___orc_rt_macho_deregister_object_symbol_table" )}; |
347 | RuntimeFunction RegisterObjectPlatformSections{ |
348 | ES.intern(SymName: "___orc_rt_macho_register_object_platform_sections" )}; |
349 | RuntimeFunction DeregisterObjectPlatformSections{ |
350 | ES.intern(SymName: "___orc_rt_macho_deregister_object_platform_sections" )}; |
351 | RuntimeFunction CreatePThreadKey{ |
352 | ES.intern(SymName: "___orc_rt_macho_create_pthread_key" )}; |
353 | RuntimeFunction RegisterObjCRuntimeObject{ |
354 | ES.intern(SymName: "___orc_rt_macho_register_objc_runtime_object" )}; |
355 | RuntimeFunction DeregisterObjCRuntimeObject{ |
356 | ES.intern(SymName: "___orc_rt_macho_deregister_objc_runtime_object" )}; |
357 | |
358 | DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols; |
359 | |
360 | std::mutex PlatformMutex; |
361 | DenseMap<JITDylib *, ExecutorAddr> ; |
362 | DenseMap<ExecutorAddr, JITDylib *> ; |
363 | DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey; |
364 | |
365 | std::atomic<BootstrapInfo *> Bootstrap; |
366 | }; |
367 | |
368 | // Generates a MachO header. |
369 | class : public MaterializationUnit { |
370 | public: |
371 | (MachOPlatform &MOP, SymbolStringPtr , |
372 | MachOPlatform::HeaderOptions Opts); |
373 | StringRef () const override { return "MachOHeaderMU" ; } |
374 | void (std::unique_ptr<MaterializationResponsibility> R) override; |
375 | void (const JITDylib &JD, const SymbolStringPtr &Sym) override; |
376 | |
377 | protected: |
378 | virtual jitlink::Block &(JITDylib &JD, jitlink::LinkGraph &G, |
379 | jitlink::Section &); |
380 | |
381 | MachOPlatform &; |
382 | MachOPlatform::HeaderOptions ; |
383 | |
384 | private: |
385 | struct { |
386 | const char *; |
387 | uint64_t ; |
388 | }; |
389 | |
390 | static constexpr HeaderSymbol [] = { |
391 | {.Name: "___mh_executable_header" , .Offset: 0}}; |
392 | |
393 | void (JITDylib &JD, jitlink::LinkGraph &G, |
394 | const SymbolStringPtr &InitializerSymbol); |
395 | static MaterializationUnit::Interface |
396 | (MachOPlatform &MOP, |
397 | const SymbolStringPtr &); |
398 | }; |
399 | |
400 | /// Simple MachO header graph builder. |
401 | inline std::unique_ptr<MaterializationUnit> |
402 | MachOPlatform::(MachOPlatform &MOP, |
403 | HeaderOptions Opts) { |
404 | return std::make_unique<SimpleMachOHeaderMU>(args&: MOP, args&: MOP.MachOHeaderStartSymbol, |
405 | args: std::move(Opts)); |
406 | } |
407 | |
408 | struct { |
409 | size_t = 0; |
410 | uint32_t = 0; |
411 | uint32_t = 0; |
412 | }; |
413 | MachOHeaderInfo (const Triple &TT); |
414 | |
415 | } // end namespace orc |
416 | } // end namespace llvm |
417 | |
418 | #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H |
419 | |