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     /// 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;
HeaderOptionsHeaderOptions70     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 
getExecutionSession()136   ExecutionSession &getExecutionSession() const { return ES; }
getObjectLinkingLayer()137   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
138 
getMachOHeaderStartSymbol()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 
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 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:
MachOPlatformPlugin(MachOPlatform & MP)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.
notifyFailed(MaterializationResponsibility & MR)196     Error notifyFailed(MaterializationResponsibility &MR) override {
197       return Error::success();
198     }
199 
notifyRemovingResources(JITDylib & JD,ResourceKey K)200     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
201       return Error::success();
202     }
203 
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)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("___dso_handle");
324 
325   struct RuntimeFunction {
RuntimeFunctionRuntimeFunction326     RuntimeFunction(SymbolStringPtr Name) : Name(std::move(Name)) {}
327     SymbolStringPtr Name;
328     ExecutorAddr Addr;
329   };
330 
331   RuntimeFunction PlatformBootstrap{
332       ES.intern("___orc_rt_macho_platform_bootstrap")};
333   RuntimeFunction PlatformShutdown{
334       ES.intern("___orc_rt_macho_platform_shutdown")};
335   RuntimeFunction RegisterEHFrameSection{
336       ES.intern("___orc_rt_macho_register_ehframe_section")};
337   RuntimeFunction DeregisterEHFrameSection{
338       ES.intern("___orc_rt_macho_deregister_ehframe_section")};
339   RuntimeFunction RegisterJITDylib{
340       ES.intern("___orc_rt_macho_register_jitdylib")};
341   RuntimeFunction DeregisterJITDylib{
342       ES.intern("___orc_rt_macho_deregister_jitdylib")};
343   RuntimeFunction RegisterObjectSymbolTable{
344       ES.intern("___orc_rt_macho_register_object_symbol_table")};
345   RuntimeFunction DeregisterObjectSymbolTable{
346       ES.intern("___orc_rt_macho_deregister_object_symbol_table")};
347   RuntimeFunction RegisterObjectPlatformSections{
348       ES.intern("___orc_rt_macho_register_object_platform_sections")};
349   RuntimeFunction DeregisterObjectPlatformSections{
350       ES.intern("___orc_rt_macho_deregister_object_platform_sections")};
351   RuntimeFunction CreatePThreadKey{
352       ES.intern("___orc_rt_macho_create_pthread_key")};
353   RuntimeFunction RegisterObjCRuntimeObject{
354       ES.intern("___orc_rt_macho_register_objc_runtime_object")};
355   RuntimeFunction DeregisterObjCRuntimeObject{
356       ES.intern("___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.
369 class SimpleMachOHeaderMU : public MaterializationUnit {
370 public:
371   SimpleMachOHeaderMU(MachOPlatform &MOP, SymbolStringPtr HeaderStartSymbol,
372                       MachOPlatform::HeaderOptions Opts);
getName()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 
377 protected:
378   virtual jitlink::Block &createHeaderBlock(JITDylib &JD, jitlink::LinkGraph &G,
379                                             jitlink::Section &HeaderSection);
380 
381   MachOPlatform &MOP;
382   MachOPlatform::HeaderOptions Opts;
383 
384 private:
385   struct HeaderSymbol {
386     const char *Name;
387     uint64_t Offset;
388   };
389 
390   static constexpr HeaderSymbol AdditionalHeaderSymbols[] = {
391       {"___mh_executable_header", 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.
401 inline std::unique_ptr<MaterializationUnit>
buildSimpleMachOHeaderMU(MachOPlatform & MOP,HeaderOptions Opts)402 MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP,
403                                         HeaderOptions Opts) {
404   return std::make_unique<SimpleMachOHeaderMU>(MOP, MOP.MachOHeaderStartSymbol,
405                                                std::move(Opts));
406 }
407 
408 struct MachOHeaderInfo {
409   size_t PageSize = 0;
410   uint32_t CPUType = 0;
411   uint32_t CPUSubType = 0;
412 };
413 MachOHeaderInfo getMachOHeaderInfoFromTriple(const Triple &TT);
414 
415 } // end namespace orc
416 } // end namespace llvm
417 
418 #endif // LLVM_EXECUTIONENGINE_ORC_MACHOPLATFORM_H
419