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("___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("___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.
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      {"___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.
401inline std::unique_ptr<MaterializationUnit>
402MachOPlatform::buildSimpleMachOHeaderMU(MachOPlatform &MOP,
403                                        HeaderOptions Opts) {
404  return std::make_unique<SimpleMachOHeaderMU>(MOP, MOP.MachOHeaderStartSymbol,
405                                               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