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