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/Memory.h"
24 #include <algorithm>
25 #include <cstdint>
26 
27 namespace llvm {
28 namespace orc {
29 
30 /// Generic ORC ABI support.
31 ///
32 /// This class can be substituted as the target architecture 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.
36 class OrcGenericABI {
37 public:
38   static const unsigned PointerSize = sizeof(uintptr_t);
39   static const unsigned TrampolineSize = 1;
40   static const unsigned ResolverCodeSize = 1;
41 
42   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
43                                             void *TrampolineId);
44 
45   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
46                                 void *CallbackMgr) {
47     llvm_unreachable("writeResolverCode is not supported by the generic host "
48                      "support class");
49   }
50 
51   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
52                                unsigned NumTrampolines) {
53     llvm_unreachable("writeTrampolines is not supported by the generic host "
54                      "support class");
55   }
56 
57   class IndirectStubsInfo {
58   public:
59     const static unsigned StubSize = 1;
60 
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"); }
64   };
65 
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");
70   }
71 };
72 
73 /// Provide information about stub blocks generated by the
74 /// makeIndirectStubsBlock function.
75 template <unsigned StubSizeVal> class GenericIndirectStubsInfo {
76 public:
77   const static unsigned StubSize = StubSizeVal;
78 
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)) {
84     Other.NumStubs = 0;
85   }
86 
87   GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) {
88     NumStubs = Other.NumStubs;
89     Other.NumStubs = 0;
90     StubsMem = std::move(Other.StubsMem);
91     return *this;
92   }
93 
94   /// Number of stubs in this block.
95   unsigned getNumStubs() const { return NumStubs; }
96 
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;
101   }
102 
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;
108   }
109 
110 private:
111   unsigned NumStubs = 0;
112   sys::OwningMemoryBlock StubsMem;
113 };
114 
115 class OrcAArch64 {
116 public:
117   static const unsigned PointerSize = 8;
118   static const unsigned TrampolineSize = 12;
119   static const unsigned ResolverCodeSize = 0x120;
120 
121   using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
122 
123   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
124                                             void *TrampolineId);
125 
126   /// Write the resolver code into the given memory. The user is
127   /// responsible for allocating the memory and setting permissions.
128   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
129                                 void *CallbackMgr);
130 
131   /// Write the requested number of trampolines into the given memory,
132   /// which must be big enough to hold 1 pointer, plus NumTrampolines
133   /// trampolines.
134   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
135                                unsigned NumTrampolines);
136 
137   /// Emit at least MinStubs worth of indirect call stubs, rounded out to
138   /// the nearest page size.
139   ///
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);
145 };
146 
147 /// X86_64 code that's common to all ABIs.
148 ///
149 /// X86_64 supports lazy JITing.
150 class OrcX86_64_Base {
151 public:
152   static const unsigned PointerSize = 8;
153   static const unsigned TrampolineSize = 8;
154 
155   using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
156 
157   /// Write the requested number of trampolines into the given memory,
158   /// which must be big enough to hold 1 pointer, plus NumTrampolines
159   /// trampolines.
160   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
161                                unsigned NumTrampolines);
162 
163   /// Emit at least MinStubs worth of indirect call stubs, rounded out to
164   /// the nearest page size.
165   ///
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);
171 };
172 
173 /// X86_64 support for SysV ABI (Linux, MacOSX).
174 ///
175 /// X86_64_SysV supports lazy JITing.
176 class OrcX86_64_SysV : public OrcX86_64_Base {
177 public:
178   static const unsigned ResolverCodeSize = 0x6C;
179 
180   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
181                                             void *TrampolineId);
182 
183   /// Write the resolver code into the given memory. The user is
184   /// responsible for allocating the memory and setting permissions.
185   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
186                                 void *CallbackMgr);
187 };
188 
189 /// X86_64 support for Win32.
190 ///
191 /// X86_64_Win32 supports lazy JITing.
192 class OrcX86_64_Win32 : public OrcX86_64_Base {
193 public:
194   static const unsigned ResolverCodeSize = 0x74;
195 
196   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
197                                             void *TrampolineId);
198 
199   /// Write the resolver code into the given memory. The user is
200   /// responsible for allocating the memory and setting permissions.
201   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
202                                 void *CallbackMgr);
203 };
204 
205 /// I386 support.
206 ///
207 /// I386 supports lazy JITing.
208 class OrcI386 {
209 public:
210   static const unsigned PointerSize = 4;
211   static const unsigned TrampolineSize = 8;
212   static const unsigned ResolverCodeSize = 0x4a;
213 
214   using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
215 
216   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
217                                             void *TrampolineId);
218 
219   /// Write the resolver code into the given memory. The user is
220   /// responsible for allocating the memory and setting permissions.
221   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
222                                 void *CallbackMgr);
223 
224   /// Write the requested number of trampolines into the given memory,
225   /// which must be big enough to hold 1 pointer, plus NumTrampolines
226   /// trampolines.
227   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
228                                unsigned NumTrampolines);
229 
230   /// Emit at least MinStubs worth of indirect call stubs, rounded out to
231   /// the nearest page size.
232   ///
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);
238 };
239 
240 // @brief Mips32 support.
241 //
242 // Mips32 supports lazy JITing.
243 class OrcMips32_Base {
244 public:
245   static const unsigned PointerSize = 4;
246   static const unsigned TrampolineSize = 20;
247   static const unsigned ResolverCodeSize = 0xfc;
248   using IndirectStubsInfo = GenericIndirectStubsInfo<16>;
249 
250   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
251                                             void *TrampolineId);
252   /// Write the requested number of trampolines into the given memory,
253   /// which must be big enough to hold 1 pointer, plus NumTrampolines
254   /// trampolines.
255   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,unsigned NumTrampolines);
256 
257   /// Write the resolver code into the given memory. The user is
258   /// responsible for allocating the memory and setting permissions.
259   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr, bool isBigEndian);
260   /// Emit at least MinStubs worth of indirect call stubs, rounded out to
261   /// the nearest page size.
262   ///
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);
267 };
268 
269 
270 class OrcMips32Le : public OrcMips32_Base {
271 public:
272   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr)
273   { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, false); }
274 };
275 
276 class OrcMips32Be : public OrcMips32_Base {
277 public:
278   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr)
279   { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, true); }
280 };
281 
282 // @brief Mips64 support.
283 //
284 // Mips64 supports lazy JITing.
285 class OrcMips64 {
286 public:
287   static const unsigned PointerSize = 8;
288   static const unsigned TrampolineSize = 40;
289   static const unsigned ResolverCodeSize = 0x120;
290 
291   using IndirectStubsInfo = GenericIndirectStubsInfo<32>;
292   using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
293                                             void *TrampolineId);
294   /// Write the resolver code into the given memory. The user is
295   /// responsible for allocating the memory and setting permissions.
296   static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr);
297 
298   /// Write the requested number of trampolines into the given memory,
299   /// which must be big enough to hold 1 pointer, plus NumTrampolines
300   /// trampolines.
301   static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,unsigned NumTrampolines);
302 
303   /// Emit at least MinStubs worth of indirect call stubs, rounded out to
304   /// the nearest page size.
305   ///
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);
310 };
311 
312  } // end namespace orc
313  } // end namespace llvm
314 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
315