1//===- OrcABISupport.h - ABI support code -----------------------*- 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// ABI specific code for Orc, e.g. callback assembly.
10//
11// ABI classes should be part of the JIT *target* process, not the host
12// process (except where you're doing hosted JITing and the two are one and the
13// same).
14//
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
18#define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
19
20#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
21#include "llvm/Support/Error.h"
22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/MathExtras.h"
24#include <cstdint>
25
26namespace llvm {
27namespace orc {
28
29struct IndirectStubsAllocationSizes {
30 uint64_t StubBytes = 0;
31 uint64_t PointerBytes = 0;
32 unsigned NumStubs = 0;
33};
34
35template <typename ORCABI>
36IndirectStubsAllocationSizes
37getIndirectStubsBlockSizes(unsigned MinStubs, unsigned RoundToMultipleOf = 0) {
38 assert(
39 (RoundToMultipleOf == 0 || (RoundToMultipleOf % ORCABI::StubSize == 0)) &&
40 "RoundToMultipleOf is not a multiple of stub size");
41 uint64_t StubBytes = MinStubs * ORCABI::StubSize;
42 if (RoundToMultipleOf)
43 StubBytes = alignTo(Value: StubBytes, Align: RoundToMultipleOf);
44 unsigned NumStubs = StubBytes / ORCABI::StubSize;
45 uint64_t PointerBytes = NumStubs * ORCABI::PointerSize;
46 return {.StubBytes: StubBytes, .PointerBytes: PointerBytes, .NumStubs: NumStubs};
47}
48
49/// Generic ORC ABI support.
50///
51/// This class can be substituted as the target architecture support class for
52/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
53/// support lazy JITing however, and any attempt to use that functionality
54/// will result in execution of an llvm_unreachable.
55class OrcGenericABI {
56public:
57 static constexpr unsigned PointerSize = sizeof(uintptr_t);
58 static constexpr unsigned TrampolineSize = 1;
59 static constexpr unsigned StubSize = 1;
60 static constexpr unsigned StubToPointerMaxDisplacement = 1;
61 static constexpr unsigned ResolverCodeSize = 1;
62
63 static void writeResolverCode(char *ResolveWorkingMem,
64 ExecutorAddr ResolverTargetAddr,
65 ExecutorAddr ReentryFnAddr,
66 ExecutorAddr ReentryCtxAddr) {
67 llvm_unreachable("writeResolverCode is not supported by the generic host "
68 "support class");
69 }
70
71 static void writeTrampolines(char *TrampolineBlockWorkingMem,
72 ExecutorAddr TrampolineBlockTargetAddr,
73 ExecutorAddr ResolverAddr,
74 unsigned NumTrampolines) {
75 llvm_unreachable("writeTrampolines is not supported by the generic host "
76 "support class");
77 }
78
79 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
80 ExecutorAddr StubsBlockTargetAddress,
81 ExecutorAddr PointersBlockTargetAddress,
82 unsigned NumStubs) {
83 llvm_unreachable(
84 "writeIndirectStubsBlock is not supported by the generic host "
85 "support class");
86 }
87};
88
89class OrcAArch64 {
90public:
91 static constexpr unsigned PointerSize = 8;
92 static constexpr unsigned TrampolineSize = 12;
93 static constexpr unsigned StubSize = 8;
94 static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27;
95 static constexpr unsigned ResolverCodeSize = 0x120;
96
97 /// Write the resolver code into the given memory. The user is
98 /// responsible for allocating the memory and setting permissions.
99 ///
100 /// ReentryFnAddr should be the address of a function whose signature matches
101 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
102 /// argument of writeResolverCode will be passed as the second argument to
103 /// the function at ReentryFnAddr.
104 static void writeResolverCode(char *ResolverWorkingMem,
105 ExecutorAddr ResolverTargetAddress,
106 ExecutorAddr ReentryFnAddr,
107 ExecutorAddr RentryCtxAddr);
108
109 /// Write the requested number of trampolines into the given memory,
110 /// which must be big enough to hold 1 pointer, plus NumTrampolines
111 /// trampolines.
112 static void writeTrampolines(char *TrampolineBlockWorkingMem,
113 ExecutorAddr TrampolineBlockTargetAddress,
114 ExecutorAddr ResolverAddr,
115 unsigned NumTrampolines);
116
117 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
118 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
119 /// Nth stub using the Nth pointer in memory starting at
120 /// PointersBlockTargetAddress.
121 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
122 ExecutorAddr StubsBlockTargetAddress,
123 ExecutorAddr PointersBlockTargetAddress,
124 unsigned MinStubs);
125};
126
127/// X86_64 code that's common to all ABIs.
128///
129/// X86_64 supports lazy JITing.
130class OrcX86_64_Base {
131public:
132 static constexpr unsigned PointerSize = 8;
133 static constexpr unsigned TrampolineSize = 8;
134 static constexpr unsigned StubSize = 8;
135 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
136
137 /// Write the requested number of trampolines into the given memory,
138 /// which must be big enough to hold 1 pointer, plus NumTrampolines
139 /// trampolines.
140 static void writeTrampolines(char *TrampolineBlockWorkingMem,
141 ExecutorAddr TrampolineBlockTargetAddress,
142 ExecutorAddr ResolverAddr,
143 unsigned NumTrampolines);
144
145 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
146 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
147 /// Nth stub using the Nth pointer in memory starting at
148 /// PointersBlockTargetAddress.
149 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
150 ExecutorAddr StubsBlockTargetAddress,
151 ExecutorAddr PointersBlockTargetAddress,
152 unsigned NumStubs);
153};
154
155/// X86_64 support for SysV ABI (Linux, MacOSX).
156///
157/// X86_64_SysV supports lazy JITing.
158class OrcX86_64_SysV : public OrcX86_64_Base {
159public:
160 static constexpr unsigned ResolverCodeSize = 0x6C;
161
162 /// Write the resolver code into the given memory. The user is
163 /// responsible for allocating the memory and setting permissions.
164 ///
165 /// ReentryFnAddr should be the address of a function whose signature matches
166 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
167 /// argument of writeResolverCode will be passed as the second argument to
168 /// the function at ReentryFnAddr.
169 static void writeResolverCode(char *ResolverWorkingMem,
170 ExecutorAddr ResolverTargetAddress,
171 ExecutorAddr ReentryFnAddr,
172 ExecutorAddr ReentryCtxAddr);
173};
174
175/// X86_64 support for Win32.
176///
177/// X86_64_Win32 supports lazy JITing.
178class OrcX86_64_Win32 : public OrcX86_64_Base {
179public:
180 static constexpr unsigned ResolverCodeSize = 0x74;
181
182 /// Write the resolver code into the given memory. The user is
183 /// responsible for allocating the memory and setting permissions.
184 ///
185 /// ReentryFnAddr should be the address of a function whose signature matches
186 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
187 /// argument of writeResolverCode will be passed as the second argument to
188 /// the function at ReentryFnAddr.
189 static void writeResolverCode(char *ResolverWorkingMem,
190 ExecutorAddr ResolverTargetAddress,
191 ExecutorAddr ReentryFnAddr,
192 ExecutorAddr ReentryCtxAddr);
193};
194
195/// I386 support.
196///
197/// I386 supports lazy JITing.
198class OrcI386 {
199public:
200 static constexpr unsigned PointerSize = 4;
201 static constexpr unsigned TrampolineSize = 8;
202 static constexpr unsigned StubSize = 8;
203 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
204 static constexpr unsigned ResolverCodeSize = 0x4a;
205
206 /// Write the resolver code into the given memory. The user is
207 /// responsible for allocating the memory and setting permissions.
208 ///
209 /// ReentryFnAddr should be the address of a function whose signature matches
210 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
211 /// argument of writeResolverCode will be passed as the second argument to
212 /// the function at ReentryFnAddr.
213 static void writeResolverCode(char *ResolverWorkingMem,
214 ExecutorAddr ResolverTargetAddress,
215 ExecutorAddr ReentryFnAddr,
216 ExecutorAddr ReentryCtxAddr);
217
218 /// Write the requested number of trampolines into the given memory,
219 /// which must be big enough to hold 1 pointer, plus NumTrampolines
220 /// trampolines.
221 static void writeTrampolines(char *TrampolineBlockWorkingMem,
222 ExecutorAddr TrampolineBlockTargetAddress,
223 ExecutorAddr ResolverAddr,
224 unsigned NumTrampolines);
225
226 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
227 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
228 /// Nth stub using the Nth pointer in memory starting at
229 /// PointersBlockTargetAddress.
230 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
231 ExecutorAddr StubsBlockTargetAddress,
232 ExecutorAddr PointersBlockTargetAddress,
233 unsigned NumStubs);
234};
235
236// @brief Mips32 support.
237//
238// Mips32 supports lazy JITing.
239class OrcMips32_Base {
240public:
241 static constexpr unsigned PointerSize = 4;
242 static constexpr unsigned TrampolineSize = 20;
243 static constexpr unsigned StubSize = 8;
244 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
245 static constexpr unsigned ResolverCodeSize = 0xfc;
246
247 /// Write the requested number of trampolines into the given memory,
248 /// which must be big enough to hold 1 pointer, plus NumTrampolines
249 /// trampolines.
250 static void writeTrampolines(char *TrampolineBlockWorkingMem,
251 ExecutorAddr TrampolineBlockTargetAddress,
252 ExecutorAddr ResolverAddr,
253 unsigned NumTrampolines);
254
255 /// Write the resolver code into the given memory. The user is
256 /// responsible for allocating the memory and setting permissions.
257 ///
258 /// ReentryFnAddr should be the address of a function whose signature matches
259 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
260 /// argument of writeResolverCode will be passed as the second argument to
261 /// the function at ReentryFnAddr.
262 static void writeResolverCode(char *ResolverBlockWorkingMem,
263 ExecutorAddr ResolverBlockTargetAddress,
264 ExecutorAddr ReentryFnAddr,
265 ExecutorAddr ReentryCtxAddr, bool isBigEndian);
266 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
267 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
268 /// Nth stub using the Nth pointer in memory starting at
269 /// PointersBlockTargetAddress.
270 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
271 ExecutorAddr StubsBlockTargetAddress,
272 ExecutorAddr PointersBlockTargetAddress,
273 unsigned NumStubs);
274};
275
276class OrcMips32Le : public OrcMips32_Base {
277public:
278 static void writeResolverCode(char *ResolverWorkingMem,
279 ExecutorAddr ResolverTargetAddress,
280 ExecutorAddr ReentryFnAddr,
281 ExecutorAddr ReentryCtxAddr) {
282 OrcMips32_Base::writeResolverCode(ResolverBlockWorkingMem: ResolverWorkingMem, ResolverBlockTargetAddress: ResolverTargetAddress,
283 ReentryFnAddr, ReentryCtxAddr, isBigEndian: false);
284 }
285};
286
287class OrcMips32Be : public OrcMips32_Base {
288public:
289 static void writeResolverCode(char *ResolverWorkingMem,
290 ExecutorAddr ResolverTargetAddress,
291 ExecutorAddr ReentryFnAddr,
292 ExecutorAddr ReentryCtxAddr) {
293 OrcMips32_Base::writeResolverCode(ResolverBlockWorkingMem: ResolverWorkingMem, ResolverBlockTargetAddress: ResolverTargetAddress,
294 ReentryFnAddr, ReentryCtxAddr, isBigEndian: true);
295 }
296};
297
298// @brief Mips64 support.
299//
300// Mips64 supports lazy JITing.
301class OrcMips64 {
302public:
303 static constexpr unsigned PointerSize = 8;
304 static constexpr unsigned TrampolineSize = 40;
305 static constexpr unsigned StubSize = 32;
306 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
307 static constexpr unsigned ResolverCodeSize = 0x120;
308
309 /// Write the resolver code into the given memory. The user is
310 /// responsible for allocating the memory and setting permissions.
311 ///
312 /// ReentryFnAddr should be the address of a function whose signature matches
313 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
314 /// argument of writeResolverCode will be passed as the second argument to
315 /// the function at ReentryFnAddr.
316 static void writeResolverCode(char *ResolverWorkingMem,
317 ExecutorAddr ResolverTargetAddress,
318 ExecutorAddr ReentryFnAddr,
319 ExecutorAddr ReentryCtxAddr);
320
321 /// Write the requested number of trampolines into the given memory,
322 /// which must be big enough to hold 1 pointer, plus NumTrampolines
323 /// trampolines.
324 static void writeTrampolines(char *TrampolineBlockWorkingMem,
325 ExecutorAddr TrampolineBlockTargetAddress,
326 ExecutorAddr ResolverFnAddr,
327 unsigned NumTrampolines);
328 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
329 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
330 /// Nth stub using the Nth pointer in memory starting at
331 /// PointersBlockTargetAddress.
332 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
333 ExecutorAddr StubsBlockTargetAddress,
334 ExecutorAddr PointersBlockTargetAddress,
335 unsigned NumStubs);
336};
337
338// @brief riscv64 support.
339//
340// RISC-V 64 supports lazy JITing.
341class OrcRiscv64 {
342public:
343 static constexpr unsigned PointerSize = 8;
344 static constexpr unsigned TrampolineSize = 16;
345 static constexpr unsigned StubSize = 16;
346 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
347 static constexpr unsigned ResolverCodeSize = 0x148;
348
349 /// Write the resolver code into the given memory. The user is
350 /// responsible for allocating the memory and setting permissions.
351 ///
352 /// ReentryFnAddr should be the address of a function whose signature matches
353 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
354 /// argument of writeResolverCode will be passed as the second argument to
355 /// the function at ReentryFnAddr.
356 static void writeResolverCode(char *ResolverWorkingMem,
357 ExecutorAddr ResolverTargetAddress,
358 ExecutorAddr ReentryFnAddr,
359 ExecutorAddr ReentryCtxAddr);
360
361 /// Write the requested number of trampolines into the given memory,
362 /// which must be big enough to hold 1 pointer, plus NumTrampolines
363 /// trampolines.
364 static void writeTrampolines(char *TrampolineBlockWorkingMem,
365 ExecutorAddr TrampolineBlockTargetAddress,
366 ExecutorAddr ResolverFnAddr,
367 unsigned NumTrampolines);
368 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
369 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
370 /// Nth stub using the Nth pointer in memory starting at
371 /// PointersBlockTargetAddress.
372 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
373 ExecutorAddr StubsBlockTargetAddress,
374 ExecutorAddr PointersBlockTargetAddress,
375 unsigned NumStubs);
376};
377
378// @brief loongarch64 support.
379//
380// LoongArch 64 supports lazy JITing.
381class OrcLoongArch64 {
382public:
383 static constexpr unsigned PointerSize = 8;
384 static constexpr unsigned TrampolineSize = 16;
385 static constexpr unsigned StubSize = 16;
386 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
387 static constexpr unsigned ResolverCodeSize = 0xc8;
388
389 /// Write the resolver code into the given memory. The user is
390 /// responsible for allocating the memory and setting permissions.
391 ///
392 /// ReentryFnAddr should be the address of a function whose signature matches
393 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
394 /// argument of writeResolverCode will be passed as the second argument to
395 /// the function at ReentryFnAddr.
396 static void writeResolverCode(char *ResolverWorkingMem,
397 ExecutorAddr ResolverTargetAddress,
398 ExecutorAddr ReentryFnAddr,
399 ExecutorAddr ReentryCtxAddr);
400
401 /// Write the requested number of trampolines into the given memory,
402 /// which must be big enough to hold 1 pointer, plus NumTrampolines
403 /// trampolines.
404 static void writeTrampolines(char *TrampolineBlockWorkingMem,
405 ExecutorAddr TrampolineBlockTargetAddress,
406 ExecutorAddr ResolverFnAddr,
407 unsigned NumTrampolines);
408
409 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
410 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
411 /// Nth stub using the Nth pointer in memory starting at
412 /// PointersBlockTargetAddress.
413 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
414 ExecutorAddr StubsBlockTargetAddress,
415 ExecutorAddr PointersBlockTargetAddress,
416 unsigned NumStubs);
417};
418
419} // end namespace orc
420} // end namespace llvm
421
422#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
423

source code of llvm/include/llvm/ExecutionEngine/Orc/OrcABISupport.h