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
28namespace llvm {
29namespace 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.
37class OrcGenericABI {
38public:
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    unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
63    void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
64    void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
65  };
66
67  static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
68                                      unsigned MinStubs, void *InitialPtrVal) {
69    llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
70                     "host support class");
71  }
72};
73
74/// @brief Provide information about stub blocks generated by the
75///        makeIndirectStubsBlock function.
76template <unsigned StubSizeVal> class GenericIndirectStubsInfo {
77public:
78  const static unsigned StubSize = StubSizeVal;
79
80  GenericIndirectStubsInfo() = default;
81  GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
82      : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
83  GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other)
84      : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
85    Other.NumStubs = 0;
86  }
87
88  GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) {
89    NumStubs = Other.NumStubs;
90    Other.NumStubs = 0;
91    StubsMem = std::move(Other.StubsMem);
92    return *this;
93  }
94
95  /// @brief Number of stubs in this block.
96  unsigned getNumStubs() const { return NumStubs; }
97
98  /// @brief 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    return static_cast<char *>(StubsMem.base()) + Idx * StubSize;
102  }
103
104  /// @brief 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    char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
108    return reinterpret_cast<void **>(PtrsBase) + Idx;
109  }
110
111private:
112  unsigned NumStubs = 0;
113  sys::OwningMemoryBlock StubsMem;
114};
115
116class OrcAArch64 {
117public:
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  /// @brief 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  /// @brief 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  /// @brief 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/// @brief X86_64 code that's common to all ABIs.
149///
150/// X86_64 supports lazy JITing.
151class OrcX86_64_Base {
152public:
153  static const unsigned PointerSize = 8;
154  static const unsigned TrampolineSize = 8;
155
156  using IndirectStubsInfo = GenericIndirectStubsInfo<8>;
157
158  /// @brief 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  /// @brief 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/// @brief X86_64 support for SysV ABI (Linux, MacOSX).
175///
176/// X86_64_SysV supports lazy JITing.
177class OrcX86_64_SysV : public OrcX86_64_Base {
178public:
179  static const unsigned ResolverCodeSize = 0x6C;
180
181  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
182                                            void *TrampolineId);
183
184  /// @brief 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/// @brief X86_64 support for Win32.
191///
192/// X86_64_Win32 supports lazy JITing.
193class OrcX86_64_Win32 : public OrcX86_64_Base {
194public:
195  static const unsigned ResolverCodeSize = 0x74;
196
197  using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr,
198                                            void *TrampolineId);
199
200  /// @brief 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/// @brief I386 support.
207///
208/// I386 supports lazy JITing.
209class OrcI386 {
210public:
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  /// @brief 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  /// @brief 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  /// @brief 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} // end namespace orc
242} // end namespace llvm
243
244#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
245