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