LLVM 22.0.0git
ELFNixPlatform.h
Go to the documentation of this file.
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"
22
23#include <future>
24#include <thread>
25#include <unordered_map>
26#include <vector>
27
28namespace llvm {
29namespace orc {
30
34};
35
36using ELFNixJITDylibDepInfo = std::vector<ExecutorAddr>;
38 std::vector<std::pair<ExecutorAddr, ELFNixJITDylibDepInfo>>;
39
44};
45
47 std::size_t
48 operator()(const std::pair<RuntimeFunction *, RuntimeFunction *> &key) const {
49 return std::hash<void *>()(key.first->Addr.toPtr<void *>()) ^
50 std::hash<void *>()(key.second->Addr.toPtr<void *>());
51 }
52};
53
55 std::size_t
56 operator()(const std::pair<RuntimeFunction *, RuntimeFunction *> &lhs,
57 const std::pair<RuntimeFunction *, RuntimeFunction *> &rhs) const {
58 return lhs.first == rhs.first && lhs.second == rhs.second;
59 }
60};
61
62using DeferredRuntimeFnMap = std::unordered_map<
63 std::pair<RuntimeFunction *, RuntimeFunction *>,
67
68/// Mediates between ELFNix initialization and ExecutionSession state.
70public:
71 /// Try to create a ELFNixPlatform instance, adding the ORC runtime to the
72 /// given JITDylib.
73 ///
74 /// The ORC runtime requires access to a number of symbols in
75 /// libc++. It is up to the caller to ensure that the required
76 /// symbols can be referenced by code added to PlatformJD. The
77 /// standard way to achieve this is to first attach dynamic library
78 /// search generators for either the given process, or for the
79 /// specific required libraries, to PlatformJD, then to create the
80 /// platform instance:
81 ///
82 /// \code{.cpp}
83 /// auto &PlatformJD = ES.createBareJITDylib("stdlib");
84 /// PlatformJD.addGenerator(
85 /// ExitOnErr(EPCDynamicLibrarySearchGenerator
86 /// ::GetForTargetProcess(EPC)));
87 /// ES.setPlatform(
88 /// ExitOnErr(ELFNixPlatform::Create(ES, ObjLayer, EPC, PlatformJD,
89 /// "/path/to/orc/runtime")));
90 /// \endcode
91 ///
92 /// Alternatively, these symbols could be added to another JITDylib that
93 /// PlatformJD links against.
94 ///
95 /// Clients are also responsible for ensuring that any JIT'd code that
96 /// depends on runtime functions (including any code using TLV or static
97 /// destructors) can reference the runtime symbols. This is usually achieved
98 /// by linking any JITDylibs containing regular code against
99 /// PlatformJD.
100 ///
101 /// By default, ELFNixPlatform will add the set of aliases returned by the
102 /// standardPlatformAliases function. This includes both required aliases
103 /// (e.g. __cxa_atexit -> __orc_rt_elf_cxa_atexit for static destructor
104 /// support), and optional aliases that provide JIT versions of common
105 /// functions (e.g. dlopen -> __orc_rt_elf_jit_dlopen). Clients can
106 /// override these defaults by passing a non-None value for the
107 /// RuntimeAliases function, in which case the client is responsible for
108 /// setting up all aliases (including the required ones).
110 Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
111 std::unique_ptr<DefinitionGenerator> OrcRuntime,
112 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
113
114 /// Construct using a path to the ORC runtime.
116 Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
117 const char *OrcRuntimePath,
118 std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
119
120 ExecutionSession &getExecutionSession() const { return ES; }
121 ObjectLinkingLayer &getObjectLinkingLayer() const { return ObjLinkingLayer; }
122
123 Error setupJITDylib(JITDylib &JD) override;
124 Error teardownJITDylib(JITDylib &JD) override;
125 Error notifyAdding(ResourceTracker &RT,
126 const MaterializationUnit &MU) override;
127 Error notifyRemoving(ResourceTracker &RT) override;
128
129 /// Returns an AliasMap containing the default aliases for the ELFNixPlatform.
130 /// This can be modified by clients when constructing the platform to add
131 /// or remove aliases.
132 static Expected<SymbolAliasMap> standardPlatformAliases(ExecutionSession &ES,
133 JITDylib &PlatformJD);
134
135 /// Returns the array of required CXX aliases.
136 static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();
137
138 /// Returns the array of standard runtime utility aliases for ELF.
140 standardRuntimeUtilityAliases();
141
142 /// Returns a list of aliases required to enable lazy compilation via the
143 /// ORC runtime.
145 standardLazyCompilationAliases();
146
147private:
148 // Data needed for bootstrap only.
149 struct BootstrapInfo {
150 std::mutex Mutex;
151 std::condition_variable CV;
152 size_t ActiveGraphs = 0;
153 ExecutorAddr ELFNixHeaderAddr;
154 DeferredRuntimeFnMap DeferredRTFnMap;
155
156 void addArgumentsToRTFnMap(
157 RuntimeFunction *func1, RuntimeFunction *func2,
160 std::lock_guard<std::mutex> Lock(Mutex);
161 auto &argList = DeferredRTFnMap[std::make_pair(func1, func2)];
162 argList.emplace_back(arg1, arg2);
163 }
164 };
165
166 // The ELFNixPlatformPlugin scans/modifies LinkGraphs to support ELF
167 // platform features including initializers, exceptions, TLV, and language
168 // runtime registration.
169 class LLVM_ABI ELFNixPlatformPlugin : public ObjectLinkingLayer::Plugin {
170 public:
171 ELFNixPlatformPlugin(ELFNixPlatform &MP) : MP(MP) {}
172
173 void modifyPassConfig(MaterializationResponsibility &MR,
174 jitlink::LinkGraph &G,
175 jitlink::PassConfiguration &Config) override;
176
177 // FIXME: We should be tentatively tracking scraped sections and discarding
178 // if the MR fails.
179 Error notifyFailed(MaterializationResponsibility &MR) override {
180 return Error::success();
181 }
182
183 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
184 return Error::success();
185 }
186
187 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
188 ResourceKey SrcKey) override {}
189
190 private:
191 Error bootstrapPipelineStart(jitlink::LinkGraph &G);
192 Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
193 Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
194
195 void addDSOHandleSupportPasses(MaterializationResponsibility &MR,
196 jitlink::PassConfiguration &Config);
197
198 void addEHAndTLVSupportPasses(MaterializationResponsibility &MR,
199 jitlink::PassConfiguration &Config,
200 bool IsBootstrapping);
201
202 Error preserveInitSections(jitlink::LinkGraph &G,
203 MaterializationResponsibility &MR);
204
205 Error registerInitSections(jitlink::LinkGraph &G, JITDylib &JD,
206 bool IsBootstrapping);
207
208 Error fixTLVSectionsAndEdges(jitlink::LinkGraph &G, JITDylib &JD);
209
210 std::mutex PluginMutex;
211 ELFNixPlatform &MP;
212 };
213
214 using PushInitializersSendResultFn =
215 unique_function<void(Expected<ELFNixJITDylibDepInfoMap>)>;
216
217 using SendSymbolAddressFn = unique_function<void(Expected<ExecutorAddr>)>;
218
219 static bool supportedTarget(const Triple &TT);
220
221 ELFNixPlatform(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
222 std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
223 Error &Err);
224
225 // Associate ELFNixPlatform JIT-side runtime support functions with handlers.
226 Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);
227
228 void pushInitializersLoop(PushInitializersSendResultFn SendResult,
229 JITDylibSP JD);
230
231 void rt_recordInitializers(PushInitializersSendResultFn SendResult,
232 ExecutorAddr JDHeader);
233
234 void rt_lookupSymbol(SendSymbolAddressFn SendResult, ExecutorAddr Handle,
235 StringRef SymbolName);
236
237 Error registerPerObjectSections(jitlink::LinkGraph &G,
238 const ELFPerObjectSectionsToRegister &POSR,
239 bool IsBootstrapping);
240
241 Expected<uint64_t> createPThreadKey();
242
243 ExecutionSession &ES;
244 JITDylib &PlatformJD;
245 ObjectLinkingLayer &ObjLinkingLayer;
246
247 SymbolStringPtr DSOHandleSymbol;
248
249 RuntimeFunction PlatformBootstrap{
250 ES.intern("__orc_rt_elfnix_platform_bootstrap")};
251 RuntimeFunction PlatformShutdown{
252 ES.intern("__orc_rt_elfnix_platform_shutdown")};
253 RuntimeFunction RegisterJITDylib{
254 ES.intern("__orc_rt_elfnix_register_jitdylib")};
255 RuntimeFunction DeregisterJITDylib{
256 ES.intern("__orc_rt_elfnix_deregister_jitdylib")};
257 RuntimeFunction RegisterObjectSections{
258 ES.intern("__orc_rt_elfnix_register_object_sections")};
259 RuntimeFunction DeregisterObjectSections{
260 ES.intern("__orc_rt_elfnix_deregister_object_sections")};
261 RuntimeFunction RegisterInitSections{
262 ES.intern("__orc_rt_elfnix_register_init_sections")};
263 RuntimeFunction DeregisterInitSections{
264 ES.intern("__orc_rt_elfnix_deregister_init_sections")};
265 RuntimeFunction CreatePThreadKey{
266 ES.intern("__orc_rt_elfnix_create_pthread_key")};
267
268 DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
269
270 // InitSeqs gets its own mutex to avoid locking the whole session when
271 // aggregating data from the jitlink.
272 std::mutex PlatformMutex;
273 std::vector<ELFPerObjectSectionsToRegister> BootstrapPOSRs;
274
275 DenseMap<ExecutorAddr, JITDylib *> HandleAddrToJITDylib;
276 DenseMap<JITDylib *, ExecutorAddr> JITDylibToHandleAddr;
277 DenseMap<JITDylib *, uint64_t> JITDylibToPThreadKey;
278
279 std::atomic<BootstrapInfo *> Bootstrap;
280};
281
282namespace shared {
283
286
287template <>
290
291public:
292 static size_t size(const ELFPerObjectSectionsToRegister &MOPOSR) {
293 return SPSELFPerObjectSectionsToRegister::AsArgList::size(
294 MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
295 }
296
297 static bool serialize(SPSOutputBuffer &OB,
298 const ELFPerObjectSectionsToRegister &MOPOSR) {
299 return SPSELFPerObjectSectionsToRegister::AsArgList::serialize(
300 OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
301 }
302
305 return SPSELFPerObjectSectionsToRegister::AsArgList::deserialize(
306 IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
307 }
308};
309
312
313} // end namespace shared
314} // end namespace orc
315} // end namespace llvm
316
317#endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
#define LLVM_ABI
Definition: Compiler.h:213
RelaxConfig Config
Definition: ELF_riscv.cpp:506
#define G(x, y, z)
Definition: MD5.cpp:56
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
Tagged union holding either a T or a Error.
Definition: Error.h:485
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
Mediates between ELFNix initialization and ExecutionSession state.
ObjectLinkingLayer & getObjectLinkingLayer() const
ExecutionSession & getExecutionSession() const
An ExecutionSession represents a running JIT program.
Definition: Core.h:1355
Represents an address in the executor process.
Represents a JIT'd dynamic library.
Definition: Core.h:902
A MaterializationUnit represents a set of symbol definitions that can be materialized as a group,...
An ObjectLayer implementation built on JITLink.
Platforms set up standard symbols and mediate interactions between dynamic initializers (e....
Definition: Core.h:1282
API to remove / transfer ownership of JIT resources.
Definition: Core.h:78
Pointer to a pooled string representing a symbol name.
Input char buffer with underflow check.
Output char buffer with overflow check.
static bool serialize(SPSOutputBuffer &OB, const ELFPerObjectSectionsToRegister &MOPOSR)
Specialize to describe how to serialize/deserialize to/from the given concrete type.
RuntimeFunction
IDs for all omp runtime library (RTL) functions.
Definition: OMPConstants.h:45
std::vector< std::pair< ExecutorAddr, ELFNixJITDylibDepInfo > > ELFNixJITDylibDepInfoMap
std::vector< ExecutorAddr > ELFNixJITDylibDepInfo
std::unordered_map< std::pair< RuntimeFunction *, RuntimeFunction * >, SmallVector< std::pair< shared::WrapperFunctionCall::ArgDataBufferType, shared::WrapperFunctionCall::ArgDataBufferType > >, FunctionPairKeyHash, FunctionPairKeyEqual > DeferredRuntimeFnMap
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1886
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:856
Represents an address range in the exceutor process.
std::size_t operator()(const std::pair< RuntimeFunction *, RuntimeFunction * > &lhs, const std::pair< RuntimeFunction *, RuntimeFunction * > &rhs) const
std::size_t operator()(const std::pair< RuntimeFunction *, RuntimeFunction * > &key) const
RuntimeFunction(SymbolStringPtr Name)