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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- OrcABISupport.h - ABI support code -----------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// ABI specific code for Orc, e.g. callback assembly.
//
// ABI classes should be part of the JIT *target* process, not the host
// process (except where you're doing hosted JITing and the two are one and the
// same).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
#define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include <cstdint>
namespace llvm {
namespace orc {
struct IndirectStubsAllocationSizes {
uint64_t StubBytes = 0;
uint64_t PointerBytes = 0;
unsigned NumStubs = 0;
};
template <typename ORCABI>
IndirectStubsAllocationSizes
getIndirectStubsBlockSizes(unsigned MinStubs, unsigned RoundToMultipleOf = 0) {
assert(
(RoundToMultipleOf == 0 || (RoundToMultipleOf % ORCABI::StubSize == 0)) &&
"RoundToMultipleOf is not a multiple of stub size");
uint64_t StubBytes = MinStubs * ORCABI::StubSize;
if (RoundToMultipleOf)
StubBytes = alignTo(StubBytes, RoundToMultipleOf);
unsigned NumStubs = StubBytes / ORCABI::StubSize;
uint64_t PointerBytes = NumStubs * ORCABI::PointerSize;
return {StubBytes, PointerBytes, NumStubs};
}
/// Generic ORC ABI support.
///
/// This class can be substituted as the target architecture support class for
/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
/// support lazy JITing however, and any attempt to use that functionality
/// will result in execution of an llvm_unreachable.
class OrcGenericABI {
public:
static constexpr unsigned PointerSize = sizeof(uintptr_t);
static constexpr unsigned TrampolineSize = 1;
static constexpr unsigned StubSize = 1;
static constexpr unsigned StubToPointerMaxDisplacement = 1;
static constexpr unsigned ResolverCodeSize = 1;
static void writeResolverCode(char *ResolveWorkingMem,
JITTargetAddress ResolverTargetAddr,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr) {
llvm_unreachable("writeResolverCode is not supported by the generic host "
"support class");
}
static void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddr,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines) {
llvm_unreachable("writeTrampolines is not supported by the generic host "
"support class");
}
static void writeIndirectStubsBlock(
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) {
llvm_unreachable(
"writeIndirectStubsBlock is not supported by the generic host "
"support class");
}
};
class OrcAArch64 {
public:
static constexpr unsigned PointerSize = 8;
static constexpr unsigned TrampolineSize = 12;
static constexpr unsigned StubSize = 8;
static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27;
static constexpr unsigned ResolverCodeSize = 0x120;
/// Write the resolver code into the given memory. The user is
/// responsible for allocating the memory and setting permissions.
///
/// ReentryFnAddr should be the address of a function whose signature matches
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
/// argument of writeResolverCode will be passed as the second argument to
/// the function at ReentryFnAddr.
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress RentryCtxAddr);
/// Write the requested number of trampolines into the given memory,
/// which must be big enough to hold 1 pointer, plus NumTrampolines
/// trampolines.
static void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddress,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines);
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
/// Nth stub using the Nth pointer in memory starting at
/// PointersBlockTargetAddress.
static void writeIndirectStubsBlock(
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress, unsigned MinStubs);
};
/// X86_64 code that's common to all ABIs.
///
/// X86_64 supports lazy JITing.
class OrcX86_64_Base {
public:
static constexpr unsigned PointerSize = 8;
static constexpr unsigned TrampolineSize = 8;
static constexpr unsigned StubSize = 8;
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
/// Write the requested number of trampolines into the given memory,
/// which must be big enough to hold 1 pointer, plus NumTrampolines
/// trampolines.
static void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddress,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines);
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
/// Nth stub using the Nth pointer in memory starting at
/// PointersBlockTargetAddress.
static void writeIndirectStubsBlock(
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
};
/// X86_64 support for SysV ABI (Linux, MacOSX).
///
/// X86_64_SysV supports lazy JITing.
class OrcX86_64_SysV : public OrcX86_64_Base {
public:
static constexpr unsigned ResolverCodeSize = 0x6C;
/// Write the resolver code into the given memory. The user is
/// responsible for allocating the memory and setting permissions.
///
/// ReentryFnAddr should be the address of a function whose signature matches
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
/// argument of writeResolverCode will be passed as the second argument to
/// the function at ReentryFnAddr.
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr);
};
/// X86_64 support for Win32.
///
/// X86_64_Win32 supports lazy JITing.
class OrcX86_64_Win32 : public OrcX86_64_Base {
public:
static constexpr unsigned ResolverCodeSize = 0x74;
/// Write the resolver code into the given memory. The user is
/// responsible for allocating the memory and setting permissions.
///
/// ReentryFnAddr should be the address of a function whose signature matches
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
/// argument of writeResolverCode will be passed as the second argument to
/// the function at ReentryFnAddr.
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr);
};
/// I386 support.
///
/// I386 supports lazy JITing.
class OrcI386 {
public:
static constexpr unsigned PointerSize = 4;
static constexpr unsigned TrampolineSize = 8;
static constexpr unsigned StubSize = 8;
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
static constexpr unsigned ResolverCodeSize = 0x4a;
/// Write the resolver code into the given memory. The user is
/// responsible for allocating the memory and setting permissions.
///
/// ReentryFnAddr should be the address of a function whose signature matches
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
/// argument of writeResolverCode will be passed as the second argument to
/// the function at ReentryFnAddr.
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr);
/// Write the requested number of trampolines into the given memory,
/// which must be big enough to hold 1 pointer, plus NumTrampolines
/// trampolines.
static void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddress,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines);
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
/// Nth stub using the Nth pointer in memory starting at
/// PointersBlockTargetAddress.
static void writeIndirectStubsBlock(
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
};
// @brief Mips32 support.
//
// Mips32 supports lazy JITing.
class OrcMips32_Base {
public:
static constexpr unsigned PointerSize = 4;
static constexpr unsigned TrampolineSize = 20;
static constexpr unsigned StubSize = 8;
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
static constexpr unsigned ResolverCodeSize = 0xfc;
/// Write the requested number of trampolines into the given memory,
/// which must be big enough to hold 1 pointer, plus NumTrampolines
/// trampolines.
static void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddress,
JITTargetAddress ResolverAddr,
unsigned NumTrampolines);
/// Write the resolver code into the given memory. The user is
/// responsible for allocating the memory and setting permissions.
///
/// ReentryFnAddr should be the address of a function whose signature matches
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
/// argument of writeResolverCode will be passed as the second argument to
/// the function at ReentryFnAddr.
static void writeResolverCode(char *ResolverBlockWorkingMem,
JITTargetAddress ResolverBlockTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr,
bool isBigEndian);
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
/// Nth stub using the Nth pointer in memory starting at
/// PointersBlockTargetAddress.
static void writeIndirectStubsBlock(
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
};
class OrcMips32Le : public OrcMips32_Base {
public:
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr) {
OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
ReentryFnAddr, ReentryCtxAddr, false);
}
};
class OrcMips32Be : public OrcMips32_Base {
public:
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr) {
OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
ReentryFnAddr, ReentryCtxAddr, true);
}
};
// @brief Mips64 support.
//
// Mips64 supports lazy JITing.
class OrcMips64 {
public:
static constexpr unsigned PointerSize = 8;
static constexpr unsigned TrampolineSize = 40;
static constexpr unsigned StubSize = 32;
static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
static constexpr unsigned ResolverCodeSize = 0x120;
/// Write the resolver code into the given memory. The user is
/// responsible for allocating the memory and setting permissions.
///
/// ReentryFnAddr should be the address of a function whose signature matches
/// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
/// argument of writeResolverCode will be passed as the second argument to
/// the function at ReentryFnAddr.
static void writeResolverCode(char *ResolverWorkingMem,
JITTargetAddress ResolverTargetAddress,
JITTargetAddress ReentryFnAddr,
JITTargetAddress ReentryCtxAddr);
/// Write the requested number of trampolines into the given memory,
/// which must be big enough to hold 1 pointer, plus NumTrampolines
/// trampolines.
static void writeTrampolines(char *TrampolineBlockWorkingMem,
JITTargetAddress TrampolineBlockTargetAddress,
JITTargetAddress ResolverFnAddr,
unsigned NumTrampolines);
/// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
/// Stubs will be written as if linked at StubsBlockTargetAddress, with the
/// Nth stub using the Nth pointer in memory starting at
/// PointersBlockTargetAddress.
static void writeIndirectStubsBlock(
char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
};
} // end namespace orc
} // end namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|