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