1 //===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // ABI specific code for Orc, e.g. callback assembly.
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
15 //===----------------------------------------------------------------------===//
17 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
18 #define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
20 #include "llvm/ExecutionEngine/JITSymbol.h"
21 #include "llvm/Support/Error.h"
22 #include "llvm/Support/ErrorHandling.h"
23 #include "llvm/Support/Memory.h"
30 /// Generic ORC ABI support.
32 /// This class can be substituted as the target architecure support class for
33 /// ORC templates that require one (e.g. IndirectStubsManagers). It does not
34 /// support lazy JITing however, and any attempt to use that functionality
35 /// will result in execution of an llvm_unreachable.
38 static const unsigned PointerSize
= sizeof(uintptr_t);
39 static const unsigned TrampolineSize
= 1;
40 static const unsigned ResolverCodeSize
= 1;
42 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
45 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,
47 llvm_unreachable("writeResolverCode is not supported by the generic host "
51 static void writeTrampolines(uint8_t *TrampolineMem
, void *ResolverAddr
,
52 unsigned NumTrampolines
) {
53 llvm_unreachable("writeTrampolines is not supported by the generic host "
57 class IndirectStubsInfo
{
59 const static unsigned StubSize
= 1;
61 unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
62 void *getStub(unsigned Idx
) const { llvm_unreachable("Not supported"); }
63 void **getPtr(unsigned Idx
) const { llvm_unreachable("Not supported"); }
66 static Error
emitIndirectStubsBlock(IndirectStubsInfo
&StubsInfo
,
67 unsigned MinStubs
, void *InitialPtrVal
) {
68 llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
69 "host support class");
73 /// Provide information about stub blocks generated by the
74 /// makeIndirectStubsBlock function.
75 template <unsigned StubSizeVal
> class GenericIndirectStubsInfo
{
77 const static unsigned StubSize
= StubSizeVal
;
79 GenericIndirectStubsInfo() = default;
80 GenericIndirectStubsInfo(unsigned NumStubs
, sys::OwningMemoryBlock StubsMem
)
81 : NumStubs(NumStubs
), StubsMem(std::move(StubsMem
)) {}
82 GenericIndirectStubsInfo(GenericIndirectStubsInfo
&&Other
)
83 : NumStubs(Other
.NumStubs
), StubsMem(std::move(Other
.StubsMem
)) {
87 GenericIndirectStubsInfo
&operator=(GenericIndirectStubsInfo
&&Other
) {
88 NumStubs
= Other
.NumStubs
;
90 StubsMem
= std::move(Other
.StubsMem
);
94 /// Number of stubs in this block.
95 unsigned getNumStubs() const { return NumStubs
; }
97 /// Get a pointer to the stub at the given index, which must be in
98 /// the range 0 .. getNumStubs() - 1.
99 void *getStub(unsigned Idx
) const {
100 return static_cast<char *>(StubsMem
.base()) + Idx
* StubSize
;
103 /// Get a pointer to the implementation-pointer at the given index,
104 /// which must be in the range 0 .. getNumStubs() - 1.
105 void **getPtr(unsigned Idx
) const {
106 char *PtrsBase
= static_cast<char *>(StubsMem
.base()) + NumStubs
* StubSize
;
107 return reinterpret_cast<void **>(PtrsBase
) + Idx
;
111 unsigned NumStubs
= 0;
112 sys::OwningMemoryBlock StubsMem
;
117 static const unsigned PointerSize
= 8;
118 static const unsigned TrampolineSize
= 12;
119 static const unsigned ResolverCodeSize
= 0x120;
121 using IndirectStubsInfo
= GenericIndirectStubsInfo
<8>;
123 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
126 /// Write the resolver code into the given memory. The user is be
127 /// responsible for allocating the memory and setting permissions.
128 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,
131 /// Write the requsted number of trampolines into the given memory,
132 /// which must be big enough to hold 1 pointer, plus NumTrampolines
134 static void writeTrampolines(uint8_t *TrampolineMem
, void *ResolverAddr
,
135 unsigned NumTrampolines
);
137 /// Emit at least MinStubs worth of indirect call stubs, rounded out to
138 /// the nearest page size.
140 /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
141 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
142 /// will return a block of 1024 (2-pages worth).
143 static Error
emitIndirectStubsBlock(IndirectStubsInfo
&StubsInfo
,
144 unsigned MinStubs
, void *InitialPtrVal
);
147 /// X86_64 code that's common to all ABIs.
149 /// X86_64 supports lazy JITing.
150 class OrcX86_64_Base
{
152 static const unsigned PointerSize
= 8;
153 static const unsigned TrampolineSize
= 8;
155 using IndirectStubsInfo
= GenericIndirectStubsInfo
<8>;
157 /// Write the requsted number of trampolines into the given memory,
158 /// which must be big enough to hold 1 pointer, plus NumTrampolines
160 static void writeTrampolines(uint8_t *TrampolineMem
, void *ResolverAddr
,
161 unsigned NumTrampolines
);
163 /// Emit at least MinStubs worth of indirect call stubs, rounded out to
164 /// the nearest page size.
166 /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
167 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
168 /// will return a block of 1024 (2-pages worth).
169 static Error
emitIndirectStubsBlock(IndirectStubsInfo
&StubsInfo
,
170 unsigned MinStubs
, void *InitialPtrVal
);
173 /// X86_64 support for SysV ABI (Linux, MacOSX).
175 /// X86_64_SysV supports lazy JITing.
176 class OrcX86_64_SysV
: public OrcX86_64_Base
{
178 static const unsigned ResolverCodeSize
= 0x6C;
180 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
183 /// Write the resolver code into the given memory. The user is be
184 /// responsible for allocating the memory and setting permissions.
185 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,
189 /// X86_64 support for Win32.
191 /// X86_64_Win32 supports lazy JITing.
192 class OrcX86_64_Win32
: public OrcX86_64_Base
{
194 static const unsigned ResolverCodeSize
= 0x74;
196 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
199 /// Write the resolver code into the given memory. The user is be
200 /// responsible for allocating the memory and setting permissions.
201 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,
207 /// I386 supports lazy JITing.
210 static const unsigned PointerSize
= 4;
211 static const unsigned TrampolineSize
= 8;
212 static const unsigned ResolverCodeSize
= 0x4a;
214 using IndirectStubsInfo
= GenericIndirectStubsInfo
<8>;
216 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
219 /// Write the resolver code into the given memory. The user is be
220 /// responsible for allocating the memory and setting permissions.
221 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,
224 /// Write the requsted number of trampolines into the given memory,
225 /// which must be big enough to hold 1 pointer, plus NumTrampolines
227 static void writeTrampolines(uint8_t *TrampolineMem
, void *ResolverAddr
,
228 unsigned NumTrampolines
);
230 /// Emit at least MinStubs worth of indirect call stubs, rounded out to
231 /// the nearest page size.
233 /// E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k
234 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
235 /// will return a block of 1024 (2-pages worth).
236 static Error
emitIndirectStubsBlock(IndirectStubsInfo
&StubsInfo
,
237 unsigned MinStubs
, void *InitialPtrVal
);
240 // @brief Mips32 support.
242 // Mips32 supports lazy JITing.
243 class OrcMips32_Base
{
245 static const unsigned PointerSize
= 4;
246 static const unsigned TrampolineSize
= 20;
247 static const unsigned ResolverCodeSize
= 0xfc;
248 using IndirectStubsInfo
= GenericIndirectStubsInfo
<16>;
250 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
252 /// @brief Write the requsted number of trampolines into the given memory,
253 /// which must be big enough to hold 1 pointer, plus NumTrampolines
255 static void writeTrampolines(uint8_t *TrampolineMem
, void *ResolverAddr
,unsigned NumTrampolines
);
257 /// @brief Write the resolver code into the given memory. The user is be
258 /// responsible for allocating the memory and setting permissions.
259 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,void *CallbackMgr
, bool isBigEndian
);
260 /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
261 /// the nearest page size.
263 /// E.g. Asking for 4 stubs on Mips32, where stubs are 8-bytes, with 4k
264 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
265 /// will return a block of 1024 (2-pages worth).
266 static Error
emitIndirectStubsBlock(IndirectStubsInfo
&StubsInfo
,unsigned MinStubs
, void *InitialPtrVal
);
270 class OrcMips32Le
: public OrcMips32_Base
{
272 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,void *CallbackMgr
)
273 { OrcMips32_Base::writeResolverCode(ResolveMem
, Reentry
, CallbackMgr
, false); }
276 class OrcMips32Be
: public OrcMips32_Base
{
278 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,void *CallbackMgr
)
279 { OrcMips32_Base::writeResolverCode(ResolveMem
, Reentry
, CallbackMgr
, true); }
282 // @brief Mips64 support.
284 // Mips64 supports lazy JITing.
287 static const unsigned PointerSize
= 8;
288 static const unsigned TrampolineSize
= 40;
289 static const unsigned ResolverCodeSize
= 0x120;
291 using IndirectStubsInfo
= GenericIndirectStubsInfo
<32>;
292 using JITReentryFn
= JITTargetAddress (*)(void *CallbackMgr
,
294 /// @brief Write the resolver code into the given memory. The user is be
295 /// responsible for allocating the memory and setting permissions.
296 static void writeResolverCode(uint8_t *ResolveMem
, JITReentryFn Reentry
,void *CallbackMgr
);
298 /// @brief Write the requsted number of trampolines into the given memory,
299 /// which must be big enough to hold 1 pointer, plus NumTrampolines
301 static void writeTrampolines(uint8_t *TrampolineMem
, void *ResolverAddr
,unsigned NumTrampolines
);
303 /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
304 /// the nearest page size.
306 /// E.g. Asking for 4 stubs on Mips64, where stubs are 8-bytes, with 4k
307 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
308 /// will return a block of 1024 (2-pages worth).
309 static Error
emitIndirectStubsBlock(IndirectStubsInfo
&StubsInfo
,unsigned MinStubs
, void *InitialPtrVal
);
312 } // end namespace orc
313 } // end namespace llvm
314 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H