xref: /llvm-project/llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h (revision 382bafc9579f40bd834b78df671ac45308310462)
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;
84     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(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
137          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(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
145          const char *OrcRuntimePath, HeaderOptions PlatformJDOpts = {},
146          MachOHeaderMUBuilder BuildMachOHeaderMU = buildSimpleMachOHeaderMU,
147          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
148 
149   ExecutionSession &getExecutionSession() const { return ES; }
150   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
151 
152   NonOwningSymbolStringPtr getMachOHeaderStartSymbol() const {
153     return NonOwningSymbolStringPtr(MachOHeaderStartSymbol);
154   }
155 
156   Error setupJITDylib(JITDylib &JD) override;
157 
158   /// Install any platform-specific symbols (e.g. `__dso_handle`) and create a
159   /// mach-o header based on the given options.
160   Error setupJITDylib(JITDylib &JD, HeaderOptions Opts);
161 
162   Error teardownJITDylib(JITDylib &JD) override;
163   Error notifyAdding(ResourceTracker &RT,
164                      const MaterializationUnit &MU) override;
165   Error notifyRemoving(ResourceTracker &RT) override;
166 
167   /// Returns an AliasMap containing the default aliases for the MachOPlatform.
168   /// This can be modified by clients when constructing the platform to add
169   /// or remove aliases.
170   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
171 
172   /// Returns the array of required CXX aliases.
173   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
174 
175   /// Returns the array of standard runtime utility aliases for MachO.
176   static ArrayRef<std::pair<const char *, const char *>>
177   standardRuntimeUtilityAliases();
178 
179   /// Returns a list of aliases required to enable lazy compilation via the
180   /// ORC runtime.
181   static ArrayRef<std::pair<const char *, const char *>>
182   standardLazyCompilationAliases();
183 
184 private:
185   using SymbolTableVector = SmallVector<
186       std::tuple<ExecutorAddr, ExecutorAddr, MachOExecutorSymbolFlags>>;
187 
188   // Data needed for bootstrap only.
189   struct BootstrapInfo {
190     std::mutex Mutex;
191     std::condition_variable CV;
192     size_t ActiveGraphs = 0;
193     shared::AllocActions DeferredAAs;
194     ExecutorAddr MachOHeaderAddr;
195     SymbolTableVector SymTab;
196   };
197 
198   // The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO
199   // platform features including initializers, exceptions, TLV, and language
200   // runtime registration.
201   class MachOPlatformPlugin : public ObjectLinkingLayer::Plugin {
202   public:
203     MachOPlatformPlugin(MachOPlatform &MP) : MP(MP) {}
204 
205     void modifyPassConfig(MaterializationResponsibility &MR,
206                           jitlink::LinkGraph &G,
207                           jitlink::PassConfiguration &Config) override;
208 
209     // FIXME: We should be tentatively tracking scraped sections and discarding
210     // if the MR fails.
211     Error notifyFailed(MaterializationResponsibility &MR) override {
212       return Error::success();
213     }
214 
215     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
216       return Error::success();
217     }
218 
219     void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
220                                      ResourceKey SrcKey) override {}
221 
222   private:
223     struct UnwindSections {
224       SmallVector<ExecutorAddrRange> CodeRanges;
225       ExecutorAddrRange DwarfSection;
226       ExecutorAddrRange CompactUnwindSection;
227     };
228 
229     struct ObjCImageInfo {
230       uint32_t Version = 0;
231       uint32_t Flags = 0;
232       /// Whether this image info can no longer be mutated, as it may have been
233       /// registered with the objc runtime.
234       bool Finalized = false;
235     };
236 
237     struct SymbolTablePair {
238       jitlink::Symbol *OriginalSym = nullptr;
239       jitlink::Symbol *NameSym = nullptr;
240     };
241     using JITSymTabVector = SmallVector<SymbolTablePair>;
242 
243     Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
244     Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
245 
246     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
247                                         MaterializationResponsibility &MR);
248 
249     Error preserveImportantSections(jitlink::LinkGraph &G,
250                                     MaterializationResponsibility &MR);
251 
252     Error processObjCImageInfo(jitlink::LinkGraph &G,
253                                MaterializationResponsibility &MR);
254     Error mergeImageInfoFlags(jitlink::LinkGraph &G,
255                               MaterializationResponsibility &MR,
256                               ObjCImageInfo &Info, uint32_t NewFlags);
257 
258     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
259 
260     std::optional<UnwindSections> findUnwindSectionInfo(jitlink::LinkGraph &G);
261     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD,
262                                          ExecutorAddr HeaderAddr,
263                                          bool InBootstrapPhase);
264 
265     Error createObjCRuntimeObject(jitlink::LinkGraph &G);
266     Error populateObjCRuntimeObject(jitlink::LinkGraph &G,
267                                     MaterializationResponsibility &MR);
268 
269     Error prepareSymbolTableRegistration(jitlink::LinkGraph &G,
270                                          JITSymTabVector &JITSymTabInfo);
271     Error addSymbolTableRegistration(jitlink::LinkGraph &G,
272                                      MaterializationResponsibility &MR,
273                                      JITSymTabVector &JITSymTabInfo,
274                                      bool InBootstrapPhase);
275 
276     std::mutex PluginMutex;
277     MachOPlatform &MP;
278 
279     // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when
280     // JITDylibs are removed.
281     DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos;
282     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
283   };
284 
285   using GetJITDylibHeaderSendResultFn =
286       unique_function<void(Expected<ExecutorAddr>)>;
287   using GetJITDylibNameSendResultFn =
288       unique_function<void(Expected<StringRef>)>;
289   using PushInitializersSendResultFn =
290       unique_function<void(Expected<MachOJITDylibDepInfoMap>)>;
291   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
292   using PushSymbolsInSendResultFn = unique_function<void(Error)>;
293 
294   static bool supportedTarget(const Triple &TT);
295 
296   static jitlink::Edge::Kind getPointerEdgeKind(jitlink::LinkGraph &G);
297 
298   static MachOExecutorSymbolFlags flagsForSymbol(jitlink::Symbol &Sym);
299 
300   MachOPlatform(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
301                 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
302                 HeaderOptions PlatformJDOpts,
303                 MachOHeaderMUBuilder BuildMachOHeaderMU, Error &Err);
304 
305   // Associate MachOPlatform JIT-side runtime support functions with handlers.
306   Error associateRuntimeSupportFunctions();
307 
308   // Implements rt_pushInitializers by making repeat async lookups for
309   // initializer symbols (each lookup may spawn more initializer symbols if
310   // it pulls in new materializers, e.g. from objects in a static library).
311   void pushInitializersLoop(PushInitializersSendResultFn SendResult,
312                             JITDylibSP JD);
313 
314   // Handle requests from the ORC runtime to push MachO initializer info.
315   void rt_pushInitializers(PushInitializersSendResultFn SendResult,
316                            ExecutorAddr JDHeaderAddr);
317 
318   // Request that that the given symbols be materialized. The bool element of
319   // each pair indicates whether the symbol must be initialized, or whether it
320   // is optional. If any required symbol is not found then the pushSymbols
321   // function will return an error.
322   void rt_pushSymbols(PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle,
323                       const std::vector<std::pair<StringRef, bool>> &Symbols);
324 
325   // Call the ORC runtime to create a pthread key.
326   Expected<uint64_t> createPThreadKey();
327 
328   ExecutionSession &ES;
329   JITDylib &PlatformJD;
330   ObjectLinkingLayer &ObjLinkingLayer;
331   MachOHeaderMUBuilder BuildMachOHeaderMU;
332 
333   SymbolStringPtr MachOHeaderStartSymbol = ES.intern("___dso_handle");
334 
335   struct RuntimeFunction {
336     RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {}
337     SymbolStringPtr Name;
338     ExecutorAddr Addr;
339   };
340 
341   RuntimeFunction PlatformBootstrap{
342       ES.intern("___orc_rt_macho_platform_bootstrap")};
343   RuntimeFunction PlatformShutdown{
344       ES.intern("___orc_rt_macho_platform_shutdown")};
345   RuntimeFunction RegisterEHFrameSection{
346       ES.intern("___orc_rt_macho_register_ehframe_section")};
347   RuntimeFunction DeregisterEHFrameSection{
348       ES.intern("___orc_rt_macho_deregister_ehframe_section")};
349   RuntimeFunction RegisterJITDylib{
350       ES.intern("___orc_rt_macho_register_jitdylib")};
351   RuntimeFunction DeregisterJITDylib{
352       ES.intern("___orc_rt_macho_deregister_jitdylib")};
353   RuntimeFunction RegisterObjectSymbolTable{
354       ES.intern("___orc_rt_macho_register_object_symbol_table")};
355   RuntimeFunction DeregisterObjectSymbolTable{
356       ES.intern("___orc_rt_macho_deregister_object_symbol_table")};
357   RuntimeFunction RegisterObjectPlatformSections{
358       ES.intern("___orc_rt_macho_register_object_platform_sections")};
359   RuntimeFunction DeregisterObjectPlatformSections{
360       ES.intern("___orc_rt_macho_deregister_object_platform_sections")};
361   RuntimeFunction CreatePThreadKey{
362       ES.intern("___orc_rt_macho_create_pthread_key")};
363   RuntimeFunction RegisterObjCRuntimeObject{
364       ES.intern("___orc_rt_macho_register_objc_runtime_object")};
365   RuntimeFunction DeregisterObjCRuntimeObject{
366       ES.intern("___orc_rt_macho_deregister_objc_runtime_object")};
367 
368   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
369 
370   std::mutex PlatformMutex;
371   BootstrapInfo *Bootstrap = nullptr;
372   DenseMap<JITDylib *, ExecutorAddr> JITDylibToHeaderAddr;
373   DenseMap<ExecutorAddr, JITDylib *> HeaderAddrToJITDylib;
374   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
375 };
376 
377 // Generates a MachO header.
378 class SimpleMachOHeaderMU : public MaterializationUnit {
379 public:
380   SimpleMachOHeaderMU(MachOPlatform &MOP, SymbolStringPtr HeaderStartSymbol,
381                       MachOPlatform::HeaderOptions Opts);
382   StringRef getName() const override { return "MachOHeaderMU"; }
383   void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
384   void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override;
385 
386 protected:
387   virtual jitlink::Block &createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
388                                             jitlink::Section &HeaderSection);
389 
390   MachOPlatform &MOP;
391   MachOPlatform::HeaderOptions Opts;
392 
393 private:
394   struct HeaderSymbol {
395     const char *Name;
396     uint64_t Offset;
397   };
398 
399   static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
400       {"___mh_executable_header", 0}};
401 
402   void addMachOHeader(JITDylib &JD, jitlink::LinkGraph &G,
403                       const SymbolStringPtr &InitializerSymbol);
404   static MaterializationUnit::Interface
405   createHeaderInterface(MachOPlatform &MOP,
406                         const SymbolStringPtr &HeaderStartSymbol);
407 };
408 
409 /// Simple MachO header graph builder.
410 inline std::unique_ptr<MaterializationUnit>
411 MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP,
412                                         HeaderOptions Opts) {
413   return std::make_unique<SimpleMachOHeaderMU>(MOP, MOP.MachOHeaderStartSymbol,
414                                                std::move(Opts));
415 }
416 
417 struct MachOHeaderInfo {
418   size_t PageSize = 0;
419   uint32_t CPUType = 0;
420   uint32_t CPUSubType = 0;
421 };
422 MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT);
423 
424 } // end namespace orc
425 } // end namespace llvm
426 
427 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
428