1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===--- EPCIndirectionUtils.h - EPC based indirection utils ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
// ExecutorProcessControl API to interact with the executor process.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
#define LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
#include <mutex>
namespace llvm {
namespace orc {
class ExecutorProcessControl;
/// Provides ExecutorProcessControl based indirect stubs, trampoline pool and
/// lazy call through manager.
class EPCIndirectionUtils {
friend class EPCIndirectionUtilsAccess;
public:
/// ABI support base class. Used to write resolver, stub, and trampoline
/// blocks.
class ABISupport {
protected:
ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
: PointerSize(PointerSize), TrampolineSize(TrampolineSize),
StubSize(StubSize),
StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
ResolverCodeSize(ResolverCodeSize) {}
public:
virtual ~ABISupport();
unsigned getPointerSize() const { return PointerSize; }
unsigned getTrampolineSize() const { return TrampolineSize; }
unsigned getStubSize() const { return StubSize; }
unsigned getStubToPointerMaxDisplacement() const {
return StubToPointerMaxDisplacement;
}
unsigned getResolverCodeSize() const { return ResolverCodeSize; }
virtual void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddr,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr) const = 0;
virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTragetAddr,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines) const = 0;
virtual void
writeIndirectStubsBlock(char *StubsBlockWorkingMem,
JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress,
unsigned NumStubs) const = 0;
private:
unsigned PointerSize = 0;
unsigned TrampolineSize = 0;
unsigned StubSize = 0;
unsigned StubToPointerMaxDisplacement = 0;
unsigned ResolverCodeSize = 0;
};
/// Create using the given ABI class.
template <typename ORCABI>
static std::unique_ptr<EPCIndirectionUtils>
CreateWithABI(ExecutorProcessControl &EPC);
/// Create based on the ExecutorProcessControl triple.
static Expected<std::unique_ptr<EPCIndirectionUtils>>
Create(ExecutorProcessControl &EPC);
/// Return a reference to the ExecutorProcessControl object.
ExecutorProcessControl &getExecutorProcessControl() const { return EPC; }
/// Return a reference to the ABISupport object for this instance.
ABISupport &getABISupport() const { return *ABI; }
/// Release memory for resources held by this instance. This *must* be called
/// prior to destruction of the class.
Error cleanup();
/// Write resolver code to the executor process and return its address.
/// This must be called before any call to createTrampolinePool or
/// createLazyCallThroughManager.
Expected<JITTargetAddress>
writeResolverBlock(JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr);
/// Returns the address of the Resolver block. Returns zero if the
/// writeResolverBlock method has not previously been called.
JITTargetAddress getResolverBlockAddress() const { return ResolverBlockAddr; }
/// Create an IndirectStubsManager for the executor process.
std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();
/// Create a TrampolinePool for the executor process.
TrampolinePool &getTrampolinePool();
/// Create a LazyCallThroughManager.
/// This function should only be called once.
LazyCallThroughManager &
createLazyCallThroughManager(ExecutionSession &ES,
JITTargetAddress ErrorHandlerAddr);
/// Create a LazyCallThroughManager for the executor process.
LazyCallThroughManager &getLazyCallThroughManager() {
assert(LCTM && "createLazyCallThroughManager must be called first");
return *LCTM;
}
private:
using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
struct IndirectStubInfo {
IndirectStubInfo() = default;
IndirectStubInfo(JITTargetAddress StubAddress,
JITTargetAddress PointerAddress)
: StubAddress(StubAddress), PointerAddress(PointerAddress) {}
JITTargetAddress StubAddress = 0;
JITTargetAddress PointerAddress = 0;
};
using IndirectStubInfoVector = std::vector<IndirectStubInfo>;
/// Create an EPCIndirectionUtils instance.
EPCIndirectionUtils(ExecutorProcessControl &EPC,
std::unique_ptr<ABISupport> ABI);
Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);
std::mutex EPCUIMutex;
ExecutorProcessControl &EPC;
std::unique_ptr<ABISupport> ABI;
JITTargetAddress ResolverBlockAddr = 0;
FinalizedAlloc ResolverBlock;
std::unique_ptr<TrampolinePool> TP;
std::unique_ptr<LazyCallThroughManager> LCTM;
std::vector<IndirectStubInfo> AvailableIndirectStubs;
std::vector<FinalizedAlloc> IndirectStubAllocs;
};
/// This will call writeResolver on the given EPCIndirectionUtils instance
/// to set up re-entry via a function that will directly return the trampoline
/// landing address.
///
/// The EPCIndirectionUtils' LazyCallThroughManager must have been previously
/// created via EPCIndirectionUtils::createLazyCallThroughManager.
///
/// The EPCIndirectionUtils' writeResolver method must not have been previously
/// called.
///
/// This function is experimental and likely subject to revision.
Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU);
namespace detail {
template <typename ORCABI>
class ABISupportImpl : public EPCIndirectionUtils::ABISupport {
public:
ABISupportImpl()
: ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
ORCABI::ResolverCodeSize) {}
void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddr,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr) const override {
ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
ReentryFnAddr, ReentryCtxAddr);
}
void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddr,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines) const override {
ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
TrampolineBlockTargetAddr, ResolverAddr,
NumTrampolines);
}
void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress,
unsigned NumStubs) const override {
ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem,
StubsBlockTargetAddress,
PointersBlockTargetAddress, NumStubs);
}
};
} // end namespace detail
template <typename ORCABI>
std::unique_ptr<EPCIndirectionUtils>
EPCIndirectionUtils::CreateWithABI(ExecutorProcessControl &EPC) {
return std::unique_ptr<EPCIndirectionUtils>(new EPCIndirectionUtils(
EPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
}
} // end namespace orc
} // end namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|