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