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 requried
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, const char *OrcRuntimePath,
98          Optional<SymbolAliasMap> RuntimeAliases = None);
99 
getExecutionSession()100   ExecutionSession &getExecutionSession() const { return ES; }
getObjectLinkingLayer()101   ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
102 
103   Error setupJITDylib(JITDylib &JD) override;
104   Error notifyAdding(ResourceTracker &RT,
105                      const MaterializationUnit &MU) override;
106   Error notifyRemoving(ResourceTracker &RT) override;
107 
108   /// Returns an AliasMap containing the default aliases for the ELFNixPlatform.
109   /// This can be modified by clients when constructing the platform to add
110   /// or remove aliases.
111   static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
112 
113   /// Returns the array of required CXX aliases.
114   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
115 
116   /// Returns the array of standard runtime utility aliases for ELF.
117   static ArrayRef<std::pair<const char *, const char *>>
118   standardRuntimeUtilityAliases();
119 
120   /// Returns true if the given section name is an initializer section.
121   static bool isInitializerSection(StringRef SecName);
122 
123 private:
124   // The ELFNixPlatformPlugin scans/modifies LinkGraphs to support ELF
125   // platform features including initializers, exceptions, TLV, and language
126   // runtime registration.
127   class ELFNixPlatformPlugin : public ObjectLinkingLayer::Plugin {
128   public:
ELFNixPlatformPlugin(ELFNixPlatform & MP)129     ELFNixPlatformPlugin(ELFNixPlatform &MP) : MP(MP) {}
130 
131     void modifyPassConfig(MaterializationResponsibility &MR,
132                           jitlink::LinkGraph &G,
133                           jitlink::PassConfiguration &Config) override;
134 
135     SyntheticSymbolDependenciesMap
136     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) override;
137 
138     // FIXME: We should be tentatively tracking scraped sections and discarding
139     // if the MR fails.
notifyFailed(MaterializationResponsibility & MR)140     Error notifyFailed(MaterializationResponsibility &MR) override {
141       return Error::success();
142     }
143 
notifyRemovingResources(ResourceKey K)144     Error notifyRemovingResources(ResourceKey K) override {
145       return Error::success();
146     }
147 
notifyTransferringResources(ResourceKey DstKey,ResourceKey SrcKey)148     void notifyTransferringResources(ResourceKey DstKey,
149                                      ResourceKey SrcKey) override {}
150 
151   private:
152     using InitSymbolDepMap =
153         DenseMap<MaterializationResponsibility *, JITLinkSymbolSet>;
154 
155     void addInitializerSupportPasses(MaterializationResponsibility &MR,
156                                      jitlink::PassConfiguration &Config);
157 
158     void addDSOHandleSupportPasses(MaterializationResponsibility &MR,
159                                    jitlink::PassConfiguration &Config);
160 
161     void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
162                                   jitlink::PassConfiguration &Config);
163 
164     Error preserveInitSections(jitlink::LinkGraph &G,
165                                MaterializationResponsibility &MR);
166 
167     Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD);
168 
169     Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
170 
171     std::mutex PluginMutex;
172     ELFNixPlatform &MP;
173     InitSymbolDepMap InitSymbolDeps;
174   };
175 
176   using SendInitializerSequenceFn =
177       unique_function<void(Expected<ELFNixJITDylibInitializerSequence>)>;
178 
179   using SendDeinitializerSequenceFn =
180       unique_function<void(Expected<ELFNixJITDylibDeinitializerSequence>)>;
181 
182   using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
183 
184   static bool supportedTarget(const Triple &TT);
185 
186   ELFNixPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
187                  JITDylib &PlatformJD,
188                  std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
189                  Error &Err);
190 
191   // Associate ELFNixPlatform JIT-side runtime support functions with handlers.
192   Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
193 
194   void getInitializersBuildSequencePhase(SendInitializerSequenceFn SendResult,
195                                          JITDylib &JD,
196                                          std::vector<JITDylibSP> DFSLinkOrder);
197 
198   void getInitializersLookupPhase(SendInitializerSequenceFn SendResult,
199                                   JITDylib &JD);
200 
201   void rt_getInitializers(SendInitializerSequenceFn SendResult,
202                           StringRef JDName);
203 
204   void rt_getDeinitializers(SendDeinitializerSequenceFn SendResult,
205                             ExecutorAddr Handle);
206 
207   void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
208                        StringRef SymbolName);
209 
210   // Records the addresses of runtime symbols used by the platform.
211   Error bootstrapELFNixRuntime(JITDylib &PlatformJD);
212 
213   Error registerInitInfo(JITDylib &JD,
214                          ArrayRef<jitlink::Section *> InitSections);
215 
216   Error registerPerObjectSections(const ELFPerObjectSectionsToRegister &POSR);
217 
218   Expected<uint64_t> createPThreadKey();
219 
220   ExecutionSession &ES;
221   ObjectLinkingLayer &ObjLinkingLayer;
222 
223   SymbolStringPtr DSOHandleSymbol;
224   std::atomic<bool> RuntimeBootstrapped{false};
225 
226   ExecutorAddr orc_rt_elfnix_platform_bootstrap;
227   ExecutorAddr orc_rt_elfnix_platform_shutdown;
228   ExecutorAddr orc_rt_elfnix_register_object_sections;
229   ExecutorAddr orc_rt_elfnix_create_pthread_key;
230 
231   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
232 
233   // InitSeqs gets its own mutex to avoid locking the whole session when
234   // aggregating data from the jitlink.
235   std::mutex PlatformMutex;
236   DenseMap<JITDylib *, ELFNixJITDylibInitializers> InitSeqs;
237   std::vector<ELFPerObjectSectionsToRegister> BootstrapPOSRs;
238 
239   DenseMap<JITTargetAddress, JITDylib *> HandleAddrToJITDylib;
240   DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
241 };
242 
243 namespace shared {
244 
245 using SPSELFPerObjectSectionsToRegister =
246     SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
247 
248 template <>
249 class SPSSerializationTraits<SPSELFPerObjectSectionsToRegister,
250                              ELFPerObjectSectionsToRegister> {
251 
252 public:
size(const ELFPerObjectSectionsToRegister & MOPOSR)253   static size_t size(const ELFPerObjectSectionsToRegister &MOPOSR) {
254     return SPSELFPerObjectSectionsToRegister::AsArgList::size(
255         MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
256   }
257 
serialize(SPSOutputBuffer & OB,const ELFPerObjectSectionsToRegister & MOPOSR)258   static bool serialize(SPSOutputBuffer &OB,
259                         const ELFPerObjectSectionsToRegister &MOPOSR) {
260     return SPSELFPerObjectSectionsToRegister::AsArgList::serialize(
261         OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
262   }
263 
deserialize(SPSInputBuffer & IB,ELFPerObjectSectionsToRegister & MOPOSR)264   static bool deserialize(SPSInputBuffer &IB,
265                           ELFPerObjectSectionsToRegister &MOPOSR) {
266     return SPSELFPerObjectSectionsToRegister::AsArgList::deserialize(
267         IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
268   }
269 };
270 
271 using SPSNamedExecutorAddrRangeSequenceMap =
272     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
273 
274 using SPSELFNixJITDylibInitializers =
275     SPSTuple<SPSString, SPSExecutorAddr, SPSNamedExecutorAddrRangeSequenceMap>;
276 
277 using SPSELFNixJITDylibInitializerSequence =
278     SPSSequence<SPSELFNixJITDylibInitializers>;
279 
280 /// Serialization traits for ELFNixJITDylibInitializers.
281 template <>
282 class SPSSerializationTraits<SPSELFNixJITDylibInitializers,
283                              ELFNixJITDylibInitializers> {
284 public:
size(const ELFNixJITDylibInitializers & MOJDIs)285   static size_t size(const ELFNixJITDylibInitializers &MOJDIs) {
286     return SPSELFNixJITDylibInitializers::AsArgList::size(
287         MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
288   }
289 
serialize(SPSOutputBuffer & OB,const ELFNixJITDylibInitializers & MOJDIs)290   static bool serialize(SPSOutputBuffer &OB,
291                         const ELFNixJITDylibInitializers &MOJDIs) {
292     return SPSELFNixJITDylibInitializers::AsArgList::serialize(
293         OB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
294   }
295 
deserialize(SPSInputBuffer & IB,ELFNixJITDylibInitializers & MOJDIs)296   static bool deserialize(SPSInputBuffer &IB,
297                           ELFNixJITDylibInitializers &MOJDIs) {
298     return SPSELFNixJITDylibInitializers::AsArgList::deserialize(
299         IB, MOJDIs.Name, MOJDIs.DSOHandleAddress, MOJDIs.InitSections);
300   }
301 };
302 
303 using SPSELFJITDylibDeinitializers = SPSEmpty;
304 
305 using SPSELFJITDylibDeinitializerSequence =
306     SPSSequence<SPSELFJITDylibDeinitializers>;
307 
308 template <>
309 class SPSSerializationTraits<SPSELFJITDylibDeinitializers,
310                              ELFNixJITDylibDeinitializers> {
311 public:
size(const ELFNixJITDylibDeinitializers & MOJDDs)312   static size_t size(const ELFNixJITDylibDeinitializers &MOJDDs) { return 0; }
313 
serialize(SPSOutputBuffer & OB,const ELFNixJITDylibDeinitializers & MOJDDs)314   static bool serialize(SPSOutputBuffer &OB,
315                         const ELFNixJITDylibDeinitializers &MOJDDs) {
316     return true;
317   }
318 
deserialize(SPSInputBuffer & IB,ELFNixJITDylibDeinitializers & MOJDDs)319   static bool deserialize(SPSInputBuffer &IB,
320                           ELFNixJITDylibDeinitializers &MOJDDs) {
321     MOJDDs = ELFNixJITDylibDeinitializers();
322     return true;
323   }
324 };
325 
326 } // end namespace shared
327 } // end namespace orc
328 } // end namespace llvm
329 
330 #endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
331