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