1 //===-- ELFNixPlatform.h -- Utilities for executing ELF 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 // Linux/BSD support for executing JIT'd ELF in Orc.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
14 #define LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_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 struct ELFPerObjectSectionsToRegister {
30   ExecutorAddrRange EHFrameSection;
31   ExecutorAddrRange ThreadDataSection;
32 };
33 
34 struct ELFNixJITDylibInitializers {
35   using SectionList = std::vector<ExecutorAddrRange>;
36 
ELFNixJITDylibInitializersELFNixJITDylibInitializers37   ELFNixJITDylibInitializers(std::string Name, ExecutorAddr DSOHandleAddress)
38       : Name(std::move(Name)), DSOHandleAddress(std::move(DSOHandleAddress)) {}
39 
40   std::string Name;
41   ExecutorAddr DSOHandleAddress;
42 
43   StringMap<SectionList> InitSections;
44 };
45 
46 class ELFNixJITDylibDeinitializers {};
47 
48 using ELFNixJITDylibInitializerSequence =
49     std::vector<ELFNixJITDylibInitializers>;
50 
51 using ELFNixJITDylibDeinitializerSequence =
52     std::vector<ELFNixJITDylibDeinitializers>;
53 
54 /// Mediates between ELFNix initialization and ExecutionSession state.
55 class ELFNixPlatform : public Platform {
56 public:
57   /// Try to create a ELFNixPlatform instance, adding the ORC runtime to the
58   /// given JITDylib.
59   ///
60   /// The ORC runtime requires access to a number of symbols in
61   /// libc++. It is up to the caller to ensure that the required
62   /// symbols can be referenced by code added to PlatformJD. The
63   /// standard way to achieve this is to first attach dynamic library
64   /// search generators for either the given process, or for the
65   /// specific required libraries, to PlatformJD, then to create the
66   /// platform instance:
67   ///
68   /// \code{.cpp}
69   ///   auto &PlatformJD = ES.createBareJITDylib("stdlib");
70   ///   PlatformJD.addGenerator(
71   ///     ExitOnErr(EPCDynamicLibrarySearchGenerator
72   ///                 ::GetForTargetProcess(EPC)));
73   ///   ES.setPlatform(
74   ///     ExitOnErr(ELFNixPlatform::Create(ES, ObjLayer, EPC, PlatformJD,
75   ///                                     "/path/to/orc/runtime")));
76   /// \endcode
77   ///
78   /// Alternatively, these symbols could be added to another JITDylib that
79   /// PlatformJD links against.
80   ///
81   /// Clients are also responsible for ensuring that any JIT'd code that
82   /// depends on runtime functions (including any code using TLV or static
83   /// destructors) can reference the runtime symbols. This is usually achieved
84   /// by linking any JITDylibs containing regular code against
85   /// PlatformJD.
86   ///
87   /// By default, ELFNixPlatform will add the set of aliases returned by the
88   /// standardPlatformAliases function. This includes both required aliases
89   /// (e.g. __cxa_atexit -> __orc_rt_elf_cxa_atexit for static destructor
90   /// support), and optional aliases that provide JIT versions of common
91   /// functions (e.g. dlopen -> __orc_rt_elf_jit_dlopen). Clients can
92   /// override these defaults by passing a non-None value for the
93   /// RuntimeAliases function, in which case the client is responsible for
94   /// setting up all aliases (including the required ones).
95   static Expected<std::unique_ptr<ELFNixPlatform>>
96   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
97          JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
98          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
99 
100   /// Construct using a path to the ORC runtime.
101   static Expected<std::unique_ptr<ELFNixPlatform>>
102   Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
103          JITDylib &PlatformJD, const char *OrcRuntimePath,
104          std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
105 
getExecutionSession()106   ExecutionSession &getExecutionSession() const { return ES; }
getObjectLinkingLayer()107   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
108 
109   Error setupJITDylib(JITDylib &JD) override;
110   Error teardownJITDylib(JITDylib &JD) override;
111   Error notifyAdding(ResourceTracker &RT,
112                      const MaterializationUnit &MU) override;
113   Error notifyRemoving(ResourceTracker &RT) override;
114 
115   /// Returns an AliasMap containing the default aliases for the ELFNixPlatform.
116   /// This can be modified by clients when constructing the platform to add
117   /// or remove aliases.
118   static Expected<SymbolAliasMap> standardPlatformAliases(ExecutionSession &ES,
119                                                           JITDylib &PlatformJD);
120 
121   /// Returns the array of required CXX aliases.
122   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
123 
124   /// Returns the array of standard runtime utility aliases for ELF.
125   static ArrayRef<std::pair<const char *, const char *>>
126   standardRuntimeUtilityAliases();
127 
128 private:
129   // The ELFNixPlatformPlugin scans/modifies LinkGraphs to support ELF
130   // platform features including initializers, exceptions, TLV, and language
131   // runtime registration.
132   class ELFNixPlatformPlugin : public ObjectLinkingLayer::Plugin {
133   public:
ELFNixPlatformPlugin(ELFNixPlatform & MP)134     ELFNixPlatformPlugin(ELFNixPlatform &MP) : MP(MP) {}
135 
136     void modifyPassConfig(MaterializationResponsibility &MR,
137                           jitlink::LinkGraph &G,
138                           jitlink::PassConfiguration &Config) override;
139 
140     SyntheticSymbolDependenciesMap
141     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
142 
143     // FIXME: We should be tentatively tracking scraped sections and discarding
144     // if the MR fails.
notifyFailed(MaterializationResponsibility & MR)145     Error notifyFailed(MaterializationResponsibility &MR) override {
146       return Error::success();
147     }
148 
notifyRemovingResources(JITDylib & JD,ResourceKey K)149     Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
150       return Error::success();
151     }
152 
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)153     void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
154                                      ResourceKey SrcKey) override {}
155 
156   private:
157     using InitSymbolDepMap =
158         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
159 
160     void addInitializerSupportPasses(MaterializationResponsibility &MR,
161                                      jitlink::PassConfiguration &Config);
162 
163     void addDSOHandleSupportPasses(MaterializationResponsibility &MR,
164                                    jitlink::PassConfiguration &Config);
165 
166     void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
167                                   jitlink::PassConfiguration &Config);
168 
169     Error preserveInitSections(jitlink::LinkGraph &G,
170                                MaterializationResponsibility &MR);
171 
172     Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD);
173 
174     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
175 
176     std::mutex PluginMutex;
177     ELFNixPlatform &MP;
178     InitSymbolDepMap InitSymbolDeps;
179   };
180 
181   using SendInitializerSequenceFn =
182       unique_function<void(Expected<ELFNixJITDylibInitializerSequence>)>;
183 
184   using SendDeinitializerSequenceFn =
185       unique_function<void(Expected<ELFNixJITDylibDeinitializerSequence>)>;
186 
187   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
188 
189   static bool supportedTarget(const Triple &TT);
190 
191   ELFNixPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
192                  JITDylib &PlatformJD,
193                  std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
194                  Error &Err);
195 
196   // Associate ELFNixPlatform JIT-side runtime support functions with handlers.
197   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
198 
199   void getInitializersBuildSequencePhase(SendInitializerSequenceFn SendResult,
200                                          JITDylib &JD,
201                                          std::vector<JITDylibSP> DFSLinkOrder);
202 
203   void getInitializersLookupPhase(SendInitializerSequenceFn SendResult,
204                                   JITDylib &JD);
205 
206   void rt_getInitializers(SendInitializerSequenceFn SendResult,
207                           StringRef JDName);
208 
209   void rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
210                             ExecutorAddr Handle);
211 
212   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
213                        StringRef SymbolName);
214 
215   // Records the addresses of runtime symbols used by the platform.
216   Error bootstrapELFNixRuntime(JITDylib &PlatformJD);
217 
218   Error registerInitInfo(JITDylib &JD,
219                          ArrayRef<jitlink::Section *> InitSections);
220 
221   Error registerPerObjectSections(const ELFPerObjectSectionsToRegister &POSR);
222 
223   Expected<uint64_t> createPThreadKey();
224 
225   ExecutionSession &ES;
226   ObjectLinkingLayer &ObjLinkingLayer;
227 
228   SymbolStringPtr DSOHandleSymbol;
229   std::atomic<bool> RuntimeBootstrapped{false};
230 
231   ExecutorAddr orc_rt_elfnix_platform_bootstrap;
232   ExecutorAddr orc_rt_elfnix_platform_shutdown;
233   ExecutorAddr orc_rt_elfnix_register_object_sections;
234   ExecutorAddr orc_rt_elfnix_create_pthread_key;
235 
236   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
237 
238   // InitSeqs gets its own mutex to avoid locking the whole session when
239   // aggregating data from the jitlink.
240   std::mutex PlatformMutex;
241   DenseMap<JITDylib *, ELFNixJITDylibInitializers> InitSeqs;
242   std::vector<ELFPerObjectSectionsToRegister> BootstrapPOSRs;
243 
244   DenseMap<ExecutorAddr, JITDylib *> HandleAddrToJITDylib;
245   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
246 };
247 
248 namespace shared {
249 
250 using SPSELFPerObjectSectionsToRegister =
251     SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
252 
253 template <>
254 class SPSSerializationTraits<SPSELFPerObjectSectionsToRegister,
255                              ELFPerObjectSectionsToRegister> {
256 
257 public:
size(const ELFPerObjectSectionsToRegister & MOPOSR)258   static size_t size(const ELFPerObjectSectionsToRegister &MOPOSR) {
259     return SPSELFPerObjectSectionsToRegister::AsArgList::size(
260         MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
261   }
262 
serialize(SPSOutputBuffer & OB,const ELFPerObjectSectionsToRegister & MOPOSR)263   static bool serialize(SPSOutputBuffer &OB,
264                         const ELFPerObjectSectionsToRegister &MOPOSR) {
265     return SPSELFPerObjectSectionsToRegister::AsArgList::serialize(
266         OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
267   }
268 
deserialize(SPSInputBuffer & IB,ELFPerObjectSectionsToRegister & MOPOSR)269   static bool deserialize(SPSInputBuffer &IB,
270                           ELFPerObjectSectionsToRegister &MOPOSR) {
271     return SPSELFPerObjectSectionsToRegister::AsArgList::deserialize(
272         IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
273   }
274 };
275 
276 using SPSNamedExecutorAddrRangeSequenceMap =
277     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
278 
279 using SPSELFNixJITDylibInitializers =
280     SPSTuple<SPSString, SPSExecutorAddr, SPSNamedExecutorAddrRangeSequenceMap>;
281 
282 using SPSELFNixJITDylibInitializerSequence =
283     SPSSequence<SPSELFNixJITDylibInitializers>;
284 
285 /// Serialization traits for ELFNixJITDylibInitializers.
286 template <>
287 class SPSSerializationTraits<SPSELFNixJITDylibInitializers,
288                              ELFNixJITDylibInitializers> {
289 public:
size(const ELFNixJITDylibInitializers & MOJDIs)290   static size_t size(const ELFNixJITDylibInitializers &MOJDIs) {
291     return SPSELFNixJITDylibInitializers::AsArgList::size(
292         MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
293   }
294 
serialize(SPSOutputBuffer & OB,const ELFNixJITDylibInitializers & MOJDIs)295   static bool serialize(SPSOutputBuffer &OB,
296                         const ELFNixJITDylibInitializers &MOJDIs) {
297     return SPSELFNixJITDylibInitializers::AsArgList::serialize(
298         OB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
299   }
300 
deserialize(SPSInputBuffer & IB,ELFNixJITDylibInitializers & MOJDIs)301   static bool deserialize(SPSInputBuffer &IB,
302                           ELFNixJITDylibInitializers &MOJDIs) {
303     return SPSELFNixJITDylibInitializers::AsArgList::deserialize(
304         IB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
305   }
306 };
307 
308 using SPSELFJITDylibDeinitializers = SPSEmpty;
309 
310 using SPSELFJITDylibDeinitializerSequence =
311     SPSSequence<SPSELFJITDylibDeinitializers>;
312 
313 template <>
314 class SPSSerializationTraits<SPSELFJITDylibDeinitializers,
315                              ELFNixJITDylibDeinitializers> {
316 public:
size(const ELFNixJITDylibDeinitializers & MOJDDs)317   static size_t size(const ELFNixJITDylibDeinitializers &MOJDDs) { return 0; }
318 
serialize(SPSOutputBuffer & OB,const ELFNixJITDylibDeinitializers & MOJDDs)319   static bool serialize(SPSOutputBuffer &OB,
320                         const ELFNixJITDylibDeinitializers &MOJDDs) {
321     return true;
322   }
323 
deserialize(SPSInputBuffer & IB,ELFNixJITDylibDeinitializers & MOJDDs)324   static bool deserialize(SPSInputBuffer &IB,
325                           ELFNixJITDylibDeinitializers &MOJDDs) {
326     MOJDDs = ELFNixJITDylibDeinitializers();
327     return true;
328   }
329 };
330 
331 } // end namespace shared
332 } // end namespace orc
333 } // end namespace llvm
334 
335 #endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
336