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/JITSymbol.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(StubBytes, RoundToMultipleOf);
44 unsigned NumStubs = StubBytes / ORCABI::StubSize;
45 uint64_t PointerBytes = NumStubs * ORCABI::PointerSize;
46 return {StubBytes, PointerBytes, 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 JITTargetAddress ResolverTargetAddr,
65 JITTargetAddress ReentryFnAddr,
66 JITTargetAddress ReentryCtxAddr) {
67 llvm_unreachable("writeResolverCode is not supported by the generic host "
68 "support class");
69 }
70
71 static void writeTrampolines(char *TrampolineBlockWorkingMem,
72 JITTargetAddress TrampolineBlockTargetAddr,
73 JITTargetAddress ResolverAddr,
74 unsigned NumTrampolines) {
75 llvm_unreachable("writeTrampolines is not supported by the generic host "
76 "support class");
77 }
78
79 static void writeIndirectStubsBlock(
80 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
81 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) {
82 llvm_unreachable(
83 "writeIndirectStubsBlock is not supported by the generic host "
84 "support class");
85 }
86};
87
88class OrcAArch64 {
89public:
90 static constexpr unsigned PointerSize = 8;
91 static constexpr unsigned TrampolineSize = 12;
92 static constexpr unsigned StubSize = 8;
93 static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27;
94 static constexpr unsigned ResolverCodeSize = 0x120;
95
96 /// Write the resolver code into the given memory. The user is
97 /// responsible for allocating the memory and setting permissions.
98 ///
99 /// ReentryFnAddr should be the address of a function whose signature matches
100 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
101 /// argument of writeResolverCode will be passed as the second argument to
102 /// the function at ReentryFnAddr.
103 static void writeResolverCode(char *ResolverWorkingMem,
104 JITTargetAddress ResolverTargetAddress,
105 JITTargetAddress ReentryFnAddr,
106 JITTargetAddress RentryCtxAddr);
107
108 /// Write the requested number of trampolines into the given memory,
109 /// which must be big enough to hold 1 pointer, plus NumTrampolines
110 /// trampolines.
111 static void writeTrampolines(char *TrampolineBlockWorkingMem,
112 JITTargetAddress TrampolineBlockTargetAddress,
113 JITTargetAddress ResolverAddr,
114 unsigned NumTrampolines);
115
116 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
117 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
118 /// Nth stub using the Nth pointer in memory starting at
119 /// PointersBlockTargetAddress.
120 static void writeIndirectStubsBlock(
121 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
122 JITTargetAddress PointersBlockTargetAddress, unsigned MinStubs);
123};
124
125/// X86_64 code that's common to all ABIs.
126///
127/// X86_64 supports lazy JITing.
128class OrcX86_64_Base {
129public:
130 static constexpr unsigned PointerSize = 8;
131 static constexpr unsigned TrampolineSize = 8;
132 static constexpr unsigned StubSize = 8;
133 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
134
135 /// Write the requested number of trampolines into the given memory,
136 /// which must be big enough to hold 1 pointer, plus NumTrampolines
137 /// trampolines.
138 static void writeTrampolines(char *TrampolineBlockWorkingMem,
139 JITTargetAddress TrampolineBlockTargetAddress,
140 JITTargetAddress ResolverAddr,
141 unsigned NumTrampolines);
142
143 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
144 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
145 /// Nth stub using the Nth pointer in memory starting at
146 /// PointersBlockTargetAddress.
147 static void writeIndirectStubsBlock(
148 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
149 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
150};
151
152/// X86_64 support for SysV ABI (Linux, MacOSX).
153///
154/// X86_64_SysV supports lazy JITing.
155class OrcX86_64_SysV : public OrcX86_64_Base {
156public:
157 static constexpr unsigned ResolverCodeSize = 0x6C;
158
159 /// Write the resolver code into the given memory. The user is
160 /// responsible for allocating the memory and setting permissions.
161 ///
162 /// ReentryFnAddr should be the address of a function whose signature matches
163 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
164 /// argument of writeResolverCode will be passed as the second argument to
165 /// the function at ReentryFnAddr.
166 static void writeResolverCode(char *ResolverWorkingMem,
167 JITTargetAddress ResolverTargetAddress,
168 JITTargetAddress ReentryFnAddr,
169 JITTargetAddress ReentryCtxAddr);
170};
171
172/// X86_64 support for Win32.
173///
174/// X86_64_Win32 supports lazy JITing.
175class OrcX86_64_Win32 : public OrcX86_64_Base {
176public:
177 static constexpr unsigned ResolverCodeSize = 0x74;
178
179 /// Write the resolver code into the given memory. The user is
180 /// responsible for allocating the memory and setting permissions.
181 ///
182 /// ReentryFnAddr should be the address of a function whose signature matches
183 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
184 /// argument of writeResolverCode will be passed as the second argument to
185 /// the function at ReentryFnAddr.
186 static void writeResolverCode(char *ResolverWorkingMem,
187 JITTargetAddress ResolverTargetAddress,
188 JITTargetAddress ReentryFnAddr,
189 JITTargetAddress ReentryCtxAddr);
190};
191
192/// I386 support.
193///
194/// I386 supports lazy JITing.
195class OrcI386 {
196public:
197 static constexpr unsigned PointerSize = 4;
198 static constexpr unsigned TrampolineSize = 8;
199 static constexpr unsigned StubSize = 8;
200 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
201 static constexpr unsigned ResolverCodeSize = 0x4a;
202
203 /// Write the resolver code into the given memory. The user is
204 /// responsible for allocating the memory and setting permissions.
205 ///
206 /// ReentryFnAddr should be the address of a function whose signature matches
207 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
208 /// argument of writeResolverCode will be passed as the second argument to
209 /// the function at ReentryFnAddr.
210 static void writeResolverCode(char *ResolverWorkingMem,
211 JITTargetAddress ResolverTargetAddress,
212 JITTargetAddress ReentryFnAddr,
213 JITTargetAddress ReentryCtxAddr);
214
215 /// Write the requested number of trampolines into the given memory,
216 /// which must be big enough to hold 1 pointer, plus NumTrampolines
217 /// trampolines.
218 static void writeTrampolines(char *TrampolineBlockWorkingMem,
219 JITTargetAddress TrampolineBlockTargetAddress,
220 JITTargetAddress ResolverAddr,
221 unsigned NumTrampolines);
222
223 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
224 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
225 /// Nth stub using the Nth pointer in memory starting at
226 /// PointersBlockTargetAddress.
227 static void writeIndirectStubsBlock(
228 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
229 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
230};
231
232// @brief Mips32 support.
233//
234// Mips32 supports lazy JITing.
235class OrcMips32_Base {
236public:
237 static constexpr unsigned PointerSize = 4;
238 static constexpr unsigned TrampolineSize = 20;
239 static constexpr unsigned StubSize = 8;
240 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
241 static constexpr unsigned ResolverCodeSize = 0xfc;
242
243 /// Write the requested number of trampolines into the given memory,
244 /// which must be big enough to hold 1 pointer, plus NumTrampolines
245 /// trampolines.
246 static void writeTrampolines(char *TrampolineBlockWorkingMem,
247 JITTargetAddress TrampolineBlockTargetAddress,
248 JITTargetAddress ResolverAddr,
249 unsigned NumTrampolines);
250
251 /// Write the resolver code into the given memory. The user is
252 /// responsible for allocating the memory and setting permissions.
253 ///
254 /// ReentryFnAddr should be the address of a function whose signature matches
255 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
256 /// argument of writeResolverCode will be passed as the second argument to
257 /// the function at ReentryFnAddr.
258 static void writeResolverCode(char *ResolverBlockWorkingMem,
259 JITTargetAddress ResolverBlockTargetAddress,
260 JITTargetAddress ReentryFnAddr,
261 JITTargetAddress ReentryCtxAddr,
262 bool isBigEndian);
263 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
264 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
265 /// Nth stub using the Nth pointer in memory starting at
266 /// PointersBlockTargetAddress.
267 static void writeIndirectStubsBlock(
268 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
269 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
270};
271
272class OrcMips32Le : public OrcMips32_Base {
273public:
274 static void writeResolverCode(char *ResolverWorkingMem,
275 JITTargetAddress ResolverTargetAddress,
276 JITTargetAddress ReentryFnAddr,
277 JITTargetAddress ReentryCtxAddr) {
278 OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
279 ReentryFnAddr, ReentryCtxAddr, false);
280 }
281};
282
283class OrcMips32Be : public OrcMips32_Base {
284public:
285 static void writeResolverCode(char *ResolverWorkingMem,
286 JITTargetAddress ResolverTargetAddress,
287 JITTargetAddress ReentryFnAddr,
288 JITTargetAddress ReentryCtxAddr) {
289 OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
290 ReentryFnAddr, ReentryCtxAddr, true);
291 }
292};
293
294// @brief Mips64 support.
295//
296// Mips64 supports lazy JITing.
297class OrcMips64 {
298public:
299 static constexpr unsigned PointerSize = 8;
300 static constexpr unsigned TrampolineSize = 40;
301 static constexpr unsigned StubSize = 32;
302 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
303 static constexpr unsigned ResolverCodeSize = 0x120;
304
305 /// Write the resolver code into the given memory. The user is
306 /// responsible for allocating the memory and setting permissions.
307 ///
308 /// ReentryFnAddr should be the address of a function whose signature matches
309 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
310 /// argument of writeResolverCode will be passed as the second argument to
311 /// the function at ReentryFnAddr.
312 static void writeResolverCode(char *ResolverWorkingMem,
313 JITTargetAddress ResolverTargetAddress,
314 JITTargetAddress ReentryFnAddr,
315 JITTargetAddress ReentryCtxAddr);
316
317 /// Write the requested number of trampolines into the given memory,
318 /// which must be big enough to hold 1 pointer, plus NumTrampolines
319 /// trampolines.
320 static void writeTrampolines(char *TrampolineBlockWorkingMem,
321 JITTargetAddress TrampolineBlockTargetAddress,
322 JITTargetAddress ResolverFnAddr,
323 unsigned NumTrampolines);
324 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
325 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
326 /// Nth stub using the Nth pointer in memory starting at
327 /// PointersBlockTargetAddress.
328 static void writeIndirectStubsBlock(
329 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
330 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
331};
332
333} // end namespace orc
334} // end namespace llvm
335
336#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
337