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
26namespace llvm {
27namespace orc {
28
29struct ELFPerObjectSectionsToRegister {
30 ExecutorAddrRange EHFrameSection;
31 ExecutorAddrRange ThreadDataSection;
32};
33
34struct ELFNixJITDylibInitializers {
35 using SectionList = std::vector<ExecutorAddrRange>;
36
37 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
46class ELFNixJITDylibDeinitializers {};
47
48using ELFNixJITDylibInitializerSequence =
49 std::vector<ELFNixJITDylibInitializers>;
50
51using ELFNixJITDylibDeinitializerSequence =
52 std::vector<ELFNixJITDylibDeinitializers>;
53
54/// Mediates between ELFNix initialization and ExecutionSession state.
55class ELFNixPlatform : public Platform {
56public:
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
106 ExecutionSession &getExecutionSession() const { return ES; }
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
128private:
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:
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.
145 Error notifyFailed(MaterializationResponsibility &MR) override {
146 return Error::success();
147 }
148
149 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
150 return Error::success();
151 }
152
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
248namespace shared {
249
250using SPSELFPerObjectSectionsToRegister =
251 SPSTuple<SPSExecutorAddrRange, SPSExecutorAddrRange>;
252
253template <>
254class SPSSerializationTraits<SPSELFPerObjectSectionsToRegister,
255 ELFPerObjectSectionsToRegister> {
256
257public:
258 static size_t size(const ELFPerObjectSectionsToRegister &MOPOSR) {
259 return SPSELFPerObjectSectionsToRegister::AsArgList::size(
260 Arg: MOPOSR.EHFrameSection, Args: MOPOSR.ThreadDataSection);
261 }
262
263 static bool serialize(SPSOutputBuffer &OB,
264 const ELFPerObjectSectionsToRegister &MOPOSR) {
265 return SPSELFPerObjectSectionsToRegister::AsArgList::serialize(
266 OB, Arg: MOPOSR.EHFrameSection, Args: MOPOSR.ThreadDataSection);
267 }
268
269 static bool deserialize(SPSInputBuffer &IB,
270 ELFPerObjectSectionsToRegister &MOPOSR) {
271 return SPSELFPerObjectSectionsToRegister::AsArgList::deserialize(
272 IB, Arg&: MOPOSR.EHFrameSection, Args&: MOPOSR.ThreadDataSection);
273 }
274};
275
276using SPSNamedExecutorAddrRangeSequenceMap =
277 SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRangeSequence>>;
278
279using SPSELFNixJITDylibInitializers =
280 SPSTuple<SPSString, SPSExecutorAddr, SPSNamedExecutorAddrRangeSequenceMap>;
281
282using SPSELFNixJITDylibInitializerSequence =
283 SPSSequence<SPSELFNixJITDylibInitializers>;
284
285/// Serialization traits for ELFNixJITDylibInitializers.
286template <>
287class SPSSerializationTraits<SPSELFNixJITDylibInitializers,
288 ELFNixJITDylibInitializers> {
289public:
290 static size_t size(const ELFNixJITDylibInitializers &MOJDIs) {
291 return SPSELFNixJITDylibInitializers::AsArgList::size(
292 Arg: MOJDIs.Name, Args: MOJDIs.DSOHandleAddress, Args: MOJDIs.InitSections);
293 }
294
295 static bool serialize(SPSOutputBuffer &OB,
296 const ELFNixJITDylibInitializers &MOJDIs) {
297 return SPSELFNixJITDylibInitializers::AsArgList::serialize(
298 OB, Arg: MOJDIs.Name, Args: MOJDIs.DSOHandleAddress, Args: MOJDIs.InitSections);
299 }
300
301 static bool deserialize(SPSInputBuffer &IB,
302 ELFNixJITDylibInitializers &MOJDIs) {
303 return SPSELFNixJITDylibInitializers::AsArgList::deserialize(
304 IB, Arg&: MOJDIs.Name, Args&: MOJDIs.DSOHandleAddress, Args&: MOJDIs.InitSections);
305 }
306};
307
308using SPSELFJITDylibDeinitializers = SPSEmpty;
309
310using SPSELFJITDylibDeinitializerSequence =
311 SPSSequence<SPSELFJITDylibDeinitializers>;
312
313template <>
314class SPSSerializationTraits<SPSELFJITDylibDeinitializers,
315 ELFNixJITDylibDeinitializers> {
316public:
317 static size_t size(const ELFNixJITDylibDeinitializers &MOJDDs) { return 0; }
318
319 static bool serialize(SPSOutputBuffer &OB,
320 const ELFNixJITDylibDeinitializers &MOJDDs) {
321 return true;
322 }
323
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

source code of llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h