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
26namespace llvm {
27namespace orc {
28
29/// Mediates between MachO initialization and ExecutionSession state.
30class MachOPlatform : public Platform {
31public:
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 // 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 HeaderOptions {
53 /// A dylib for use with a dylib command (e.g. LC_ID_DYLIB, LC_LOAD_DYLIB).
54 struct Dylib {
55 std::string Name;
56 uint32_t Timestamp;
57 uint32_t CurrentVersion;
58 uint32_t CompatibilityVersion;
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> IDDylib;
64 /// List of LC_LOAD_DYLIBs.
65 std::vector<Dylib> LoadDylibs;
66 /// List of LC_RPATHs.
67 std::vector<std::string> RPaths;
68
69 HeaderOptions() = default;
70 HeaderOptions(Dylib D) : IDDylib(std::move(D)) {}
71 };
72
73 /// Used by setupJITDylib to create MachO header MaterializationUnits for
74 /// JITDylibs.
75 using MachOHeaderMUBuilder =
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 BuildMachOHeaderMU = 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 Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
131 JITDylib &PlatformJD, const char *OrcRuntimePath,
132 HeaderOptions PlatformJDOpts = {},
133 MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU,
134 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
135
136 ExecutionSession &getExecutionSession() const { return ES; }
137 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
138
139 NonOwningSymbolStringPtr getMachOHeaderStartSymbol() 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 setupJITDylib(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
166private:
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 MachOHeaderAddr;
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 associateJITDylibHeaderSymbol(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> HeaderAddrs;
271 InitSymbolDepMap InitSymbolDeps;
272 };
273
274 using GetJITDylibHeaderSendResultFn =
275 unique_function<void(Expected<ExecutorAddr>)>;
276 using GetJITDylibNameSendResultFn =
277 unique_function<void(Expected<StringRef>)>;
278 using PushInitializersSendResultFn =
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 BuildMachOHeaderMU, 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 JDHeaderAddr);
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 BuildMachOHeaderMU;
322
323 SymbolStringPtr MachOHeaderStartSymbol = 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> JITDylibToHeaderAddr;
362 DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
363 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
364
365 std::atomic<BootstrapInfo *> Bootstrap;
366};
367
368// Generates a MachO header.
369class SimpleMachOHeaderMU : public MaterializationUnit {
370public:
371 SimpleMachOHeaderMU(MachOPlatform &MOP, SymbolStringPtr HeaderStartSymbol,
372 MachOPlatform::HeaderOptions Opts);
373 StringRef getName() const override { return "MachOHeaderMU"; }
374 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
375 void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override;
376
377protected:
378 virtual jitlink::Block &createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
379 jitlink::Section &HeaderSection);
380
381 MachOPlatform &MOP;
382 MachOPlatform::HeaderOptions Opts;
383
384private:
385 struct HeaderSymbol {
386 const char *Name;
387 uint64_t Offset;
388 };
389
390 static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
391 {.Name: "___mh_executable_header", .Offset: 0}};
392
393 void addMachOHeader(JITDylib &JD, jitlink::LinkGraph &G,
394 const SymbolStringPtr &InitializerSymbol);
395 static MaterializationUnit::Interface
396 createHeaderInterface(MachOPlatform &MOP,
397 const SymbolStringPtr &HeaderStartSymbol);
398};
399
400/// Simple MachO header graph builder.
401inline std::unique_ptr<MaterializationUnit>
402MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP,
403 HeaderOptions Opts) {
404 return std::make_unique<SimpleMachOHeaderMU>(args&: MOP, args&: MOP.MachOHeaderStartSymbol,
405 args: std::move(Opts));
406}
407
408struct MachOHeaderInfo {
409 size_t PageSize = 0;
410 uint32_t CPUType = 0;
411 uint32_t CPUSubType = 0;
412};
413MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT);
414
415} // end namespace orc
416} // end namespace llvm
417
418#endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
419

source code of llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h