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