Line data Source code
1 : //===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // ABI specific code for Orc, e.g. callback assembly.
11 : //
12 : // ABI classes should be part of the JIT *target* process, not the host
13 : // process (except where you're doing hosted JITing and the two are one and the
14 : // same).
15 : //
16 : //===----------------------------------------------------------------------===//
17 :
18 : #ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
19 : #define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
20 :
21 : #include "llvm/ExecutionEngine/JITSymbol.h"
22 : #include "llvm/Support/Error.h"
23 : #include "llvm/Support/ErrorHandling.h"
24 : #include "llvm/Support/Memory.h"
25 : #include <algorithm>
26 : #include <cstdint>
27 :
28 : namespace llvm {
29 : namespace orc {
30 :
31 : /// Generic ORC ABI support.
32 : ///
33 : /// This class can be substituted as the target architecure support class for
34 : /// ORC templates that require one (e.g. IndirectStubsManagers). It does not
35 : /// support lazy JITing however, and any attempt to use that functionality
36 : /// will result in execution of an llvm_unreachable.
37 : class OrcGenericABI {
38 : public:
39 : static const unsigned PointerSize = sizeof(uintptr_t);
40 : static const unsigned TrampolineSize = 1;
41 : static const unsigned ResolverCodeSize = 1;
42 :
43 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
44 : void *TrampolineId);
45 :
46 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
47 : void *CallbackMgr) {
48 : llvm_unreachable("writeResolverCode is not supported by the generic host "
49 : "support class");
50 : }
51 :
52 : static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
53 : unsigned NumTrampolines) {
54 : llvm_unreachable("writeTrampolines is not supported by the generic host "
55 : "support class");
56 : }
57 :
58 : class IndirectStubsInfo {
59 : public:
60 : const static unsigned StubSize = 1;
61 :
62 0 : unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
63 0 : void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
64 0 : void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
65 : };
66 :
67 0 : static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
68 : unsigned MinStubs, void *InitialPtrVal) {
69 0 : llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
70 : "host support class");
71 : }
72 : };
73 :
74 : /// Provide information about stub blocks generated by the
75 : /// makeIndirectStubsBlock function.
76 14 : template <unsigned StubSizeVal> class GenericIndirectStubsInfo {
77 : public:
78 : const static unsigned StubSize = StubSizeVal;
79 :
80 14 : GenericIndirectStubsInfo() = default;
81 14 : GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
82 : : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
83 14 : GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other)
84 14 : : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
85 14 : Other.NumStubs = 0;
86 : }
87 :
88 : GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) {
89 14 : NumStubs = Other.NumStubs;
90 14 : Other.NumStubs = 0;
91 : StubsMem = std::move(Other.StubsMem);
92 : return *this;
93 : }
94 :
95 : /// Number of stubs in this block.
96 0 : unsigned getNumStubs() const { return NumStubs; }
97 :
98 : /// Get a pointer to the stub at the given index, which must be in
99 : /// the range 0 .. getNumStubs() - 1.
100 : void *getStub(unsigned Idx) const {
101 21 : return static_cast<char *>(StubsMem.base()) + Idx * StubSize;
102 : }
103 :
104 : /// Get a pointer to the implementation-pointer at the given index,
105 : /// which must be in the range 0 .. getNumStubs() - 1.
106 : void **getPtr(unsigned Idx) const {
107 41 : char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
108 41 : return reinterpret_cast<void **>(PtrsBase) + Idx;
109 : }
110 :
111 : private:
112 : unsigned NumStubs = 0;
113 : sys::OwningMemoryBlock StubsMem;
114 : };
115 :
116 : class OrcAArch64 {
117 : public:
118 : static const unsigned PointerSize = 8;
119 : static const unsigned TrampolineSize = 12;
120 : static const unsigned ResolverCodeSize = 0x120;
121 :
122 : using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
123 :
124 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
125 : void *TrampolineId);
126 :
127 : /// Write the resolver code into the given memory. The user is be
128 : /// responsible for allocating the memory and setting permissions.
129 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
130 : void *CallbackMgr);
131 :
132 : /// Write the requsted number of trampolines into the given memory,
133 : /// which must be big enough to hold 1 pointer, plus NumTrampolines
134 : /// trampolines.
135 : static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
136 : unsigned NumTrampolines);
137 :
138 : /// Emit at least MinStubs worth of indirect call stubs, rounded out to
139 : /// the nearest page size.
140 : ///
141 : /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
142 : /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
143 : /// will return a block of 1024 (2-pages worth).
144 : static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
145 : unsigned MinStubs, void *InitialPtrVal);
146 : };
147 :
148 : /// X86_64 code that's common to all ABIs.
149 : ///
150 : /// X86_64 supports lazy JITing.
151 : class OrcX86_64_Base {
152 : public:
153 : static const unsigned PointerSize = 8;
154 : static const unsigned TrampolineSize = 8;
155 :
156 : using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
157 :
158 : /// Write the requsted number of trampolines into the given memory,
159 : /// which must be big enough to hold 1 pointer, plus NumTrampolines
160 : /// trampolines.
161 : static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
162 : unsigned NumTrampolines);
163 :
164 : /// Emit at least MinStubs worth of indirect call stubs, rounded out to
165 : /// the nearest page size.
166 : ///
167 : /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k
168 : /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
169 : /// will return a block of 1024 (2-pages worth).
170 : static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
171 : unsigned MinStubs, void *InitialPtrVal);
172 : };
173 :
174 : /// X86_64 support for SysV ABI (Linux, MacOSX).
175 : ///
176 : /// X86_64_SysV supports lazy JITing.
177 : class OrcX86_64_SysV : public OrcX86_64_Base {
178 : public:
179 : static const unsigned ResolverCodeSize = 0x6C;
180 :
181 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
182 : void *TrampolineId);
183 :
184 : /// Write the resolver code into the given memory. The user is be
185 : /// responsible for allocating the memory and setting permissions.
186 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
187 : void *CallbackMgr);
188 : };
189 :
190 : /// X86_64 support for Win32.
191 : ///
192 : /// X86_64_Win32 supports lazy JITing.
193 : class OrcX86_64_Win32 : public OrcX86_64_Base {
194 : public:
195 : static const unsigned ResolverCodeSize = 0x74;
196 :
197 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
198 : void *TrampolineId);
199 :
200 : /// Write the resolver code into the given memory. The user is be
201 : /// responsible for allocating the memory and setting permissions.
202 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
203 : void *CallbackMgr);
204 : };
205 :
206 : /// I386 support.
207 : ///
208 : /// I386 supports lazy JITing.
209 : class OrcI386 {
210 : public:
211 : static const unsigned PointerSize = 4;
212 : static const unsigned TrampolineSize = 8;
213 : static const unsigned ResolverCodeSize = 0x4a;
214 :
215 : using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
216 :
217 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
218 : void *TrampolineId);
219 :
220 : /// Write the resolver code into the given memory. The user is be
221 : /// responsible for allocating the memory and setting permissions.
222 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
223 : void *CallbackMgr);
224 :
225 : /// Write the requsted number of trampolines into the given memory,
226 : /// which must be big enough to hold 1 pointer, plus NumTrampolines
227 : /// trampolines.
228 : static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
229 : unsigned NumTrampolines);
230 :
231 : /// Emit at least MinStubs worth of indirect call stubs, rounded out to
232 : /// the nearest page size.
233 : ///
234 : /// E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k
235 : /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
236 : /// will return a block of 1024 (2-pages worth).
237 : static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
238 : unsigned MinStubs, void *InitialPtrVal);
239 : };
240 :
241 : // @brief Mips32 support.
242 : //
243 : // Mips32 supports lazy JITing.
244 : class OrcMips32_Base {
245 : public:
246 : static const unsigned PointerSize = 4;
247 : static const unsigned TrampolineSize = 20;
248 : static const unsigned ResolverCodeSize = 0xfc;
249 : using IndirectStubsInfo = GenericIndirectStubsInfo<16>;
250 :
251 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
252 : void *TrampolineId);
253 : /// @brief Write the requsted number of trampolines into the given memory,
254 : /// which must be big enough to hold 1 pointer, plus NumTrampolines
255 : /// trampolines.
256 : static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,unsigned NumTrampolines);
257 :
258 : /// @brief Write the resolver code into the given memory. The user is be
259 : /// responsible for allocating the memory and setting permissions.
260 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr, bool isBigEndian);
261 : /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
262 : /// the nearest page size.
263 : ///
264 : /// E.g. Asking for 4 stubs on Mips32, where stubs are 8-bytes, with 4k
265 : /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
266 : /// will return a block of 1024 (2-pages worth).
267 : static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,unsigned MinStubs, void *InitialPtrVal);
268 : };
269 :
270 :
271 : class OrcMips32Le : public OrcMips32_Base {
272 : public:
273 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr)
274 0 : { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, false); }
275 : };
276 :
277 : class OrcMips32Be : public OrcMips32_Base {
278 : public:
279 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr)
280 0 : { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, true); }
281 : };
282 :
283 : // @brief Mips64 support.
284 : //
285 : // Mips64 supports lazy JITing.
286 : class OrcMips64 {
287 : public:
288 : static const unsigned PointerSize = 8;
289 : static const unsigned TrampolineSize = 40;
290 : static const unsigned ResolverCodeSize = 0x11C;
291 :
292 : using IndirectStubsInfo = GenericIndirectStubsInfo<32>;
293 : using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
294 : void *TrampolineId);
295 : /// @brief Write the resolver code into the given memory. The user is be
296 : /// responsible for allocating the memory and setting permissions.
297 : static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr);
298 :
299 : /// @brief Write the requsted number of trampolines into the given memory,
300 : /// which must be big enough to hold 1 pointer, plus NumTrampolines
301 : /// trampolines.
302 : static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,unsigned NumTrampolines);
303 :
304 : /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to
305 : /// the nearest page size.
306 : ///
307 : /// E.g. Asking for 4 stubs on Mips64, where stubs are 8-bytes, with 4k
308 : /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513
309 : /// will return a block of 1024 (2-pages worth).
310 : static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,unsigned MinStubs, void *InitialPtrVal);
311 : };
312 :
313 : } // end namespace orc
314 : } // end namespace llvm
315 : #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
|