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