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 "IndirectionUtils.h" 22 #include "llvm/Support/Memory.h" 23 #include "llvm/Support/Process.h" 24 25 namespace llvm { 26 namespace orc { 27 28 /// Generic ORC ABI support. 29 /// 30 /// This class can be substituted as the target architecure support class for 31 /// ORC templates that require one (e.g. IndirectStubsManagers). It does not 32 /// support lazy JITing however, and any attempt to use that functionality 33 /// will result in execution of an llvm_unreachable. 34 class OrcGenericABI { 35 public: 36 static const unsigned PointerSize = sizeof(uintptr_t); 37 static const unsigned TrampolineSize = 1; 38 static const unsigned ResolverCodeSize = 1; 39 40 typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); 41 42 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, 43 void *CallbackMgr) { 44 llvm_unreachable("writeResolverCode is not supported by the generic host " 45 "support class"); 46 } 47 48 static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, 49 unsigned NumTrampolines) { 50 llvm_unreachable("writeTrampolines is not supported by the generic host " 51 "support class"); 52 } 53 54 class IndirectStubsInfo { 55 public: 56 const static unsigned StubSize = 1; 57 unsigned getNumStubs() const { llvm_unreachable("Not supported"); } 58 void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); } 59 void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); } 60 }; 61 62 static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, 63 unsigned MinStubs, void *InitialPtrVal) { 64 llvm_unreachable("emitIndirectStubsBlock is not supported by the generic " 65 "host support class"); 66 } 67 }; 68 69 /// @brief Provide information about stub blocks generated by the 70 /// makeIndirectStubsBlock function. 71 template <unsigned StubSizeVal> class GenericIndirectStubsInfo { 72 public: 73 const static unsigned StubSize = StubSizeVal; 74 75 GenericIndirectStubsInfo() : NumStubs(0) {} 76 GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem) 77 : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {} 78 GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other) 79 : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) { 80 Other.NumStubs = 0; 81 } 82 GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) { 83 NumStubs = Other.NumStubs; 84 Other.NumStubs = 0; 85 StubsMem = std::move(Other.StubsMem); 86 return *this; 87 } 88 89 /// @brief Number of stubs in this block. 90 unsigned getNumStubs() const { return NumStubs; } 91 92 /// @brief Get a pointer to the stub at the given index, which must be in 93 /// the range 0 .. getNumStubs() - 1. 94 void *getStub(unsigned Idx) const { 95 return static_cast<char *>(StubsMem.base()) + Idx * StubSize; 96 } 97 98 /// @brief Get a pointer to the implementation-pointer at the given index, 99 /// which must be in the range 0 .. getNumStubs() - 1. 100 void **getPtr(unsigned Idx) const { 101 char *PtrsBase = static_cast<char *>(StubsMem.base()) + NumStubs * StubSize; 102 return reinterpret_cast<void **>(PtrsBase) + Idx; 103 } 104 105 private: 106 unsigned NumStubs; 107 sys::OwningMemoryBlock StubsMem; 108 }; 109 110 class OrcAArch64 { 111 public: 112 static const unsigned PointerSize = 8; 113 static const unsigned TrampolineSize = 12; 114 static const unsigned ResolverCodeSize = 0x120; 115 116 typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; 117 118 typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); 119 120 /// @brief Write the resolver code into the given memory. The user is be 121 /// responsible for allocating the memory and setting permissions. 122 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, 123 void *CallbackMgr); 124 125 /// @brief Write the requsted number of trampolines into the given memory, 126 /// which must be big enough to hold 1 pointer, plus NumTrampolines 127 /// trampolines. 128 static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, 129 unsigned NumTrampolines); 130 131 /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to 132 /// the nearest page size. 133 /// 134 /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k 135 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 136 /// will return a block of 1024 (2-pages worth). 137 static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, 138 unsigned MinStubs, void *InitialPtrVal); 139 }; 140 141 /// @brief X86_64 code that's common to all ABIs. 142 /// 143 /// X86_64 supports lazy JITing. 144 class OrcX86_64_Base { 145 public: 146 static const unsigned PointerSize = 8; 147 static const unsigned TrampolineSize = 8; 148 149 typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; 150 151 /// @brief Write the requsted number of trampolines into the given memory, 152 /// which must be big enough to hold 1 pointer, plus NumTrampolines 153 /// trampolines. 154 static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, 155 unsigned NumTrampolines); 156 157 /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to 158 /// the nearest page size. 159 /// 160 /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k 161 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 162 /// will return a block of 1024 (2-pages worth). 163 static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, 164 unsigned MinStubs, void *InitialPtrVal); 165 }; 166 167 /// @brief X86_64 support for SysV ABI (Linux, MacOSX). 168 /// 169 /// X86_64_SysV supports lazy JITing. 170 class OrcX86_64_SysV : public OrcX86_64_Base { 171 public: 172 static const unsigned ResolverCodeSize = 0x6C; 173 typedef TargetAddress(*JITReentryFn)(void *CallbackMgr, void *TrampolineId); 174 175 /// @brief Write the resolver code into the given memory. The user is be 176 /// responsible for allocating the memory and setting permissions. 177 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, 178 void *CallbackMgr); 179 }; 180 181 /// @brief X86_64 support for Win32. 182 /// 183 /// X86_64_Win32 supports lazy JITing. 184 class OrcX86_64_Win32 : public OrcX86_64_Base { 185 public: 186 static const unsigned ResolverCodeSize = 0x74; 187 typedef TargetAddress(*JITReentryFn)(void *CallbackMgr, void *TrampolineId); 188 189 /// @brief Write the resolver code into the given memory. The user is be 190 /// responsible for allocating the memory and setting permissions. 191 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, 192 void *CallbackMgr); 193 }; 194 195 /// @brief I386 support. 196 /// 197 /// I386 supports lazy JITing. 198 class OrcI386 { 199 public: 200 static const unsigned PointerSize = 4; 201 static const unsigned TrampolineSize = 8; 202 static const unsigned ResolverCodeSize = 0x4a; 203 204 typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; 205 206 typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId); 207 208 /// @brief Write the resolver code into the given memory. The user is be 209 /// responsible for allocating the memory and setting permissions. 210 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, 211 void *CallbackMgr); 212 213 /// @brief Write the requsted number of trampolines into the given memory, 214 /// which must be big enough to hold 1 pointer, plus NumTrampolines 215 /// trampolines. 216 static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, 217 unsigned NumTrampolines); 218 219 /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to 220 /// the nearest page size. 221 /// 222 /// E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k 223 /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 224 /// will return a block of 1024 (2-pages worth). 225 static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, 226 unsigned MinStubs, void *InitialPtrVal); 227 }; 228 229 } // End namespace orc. 230 } // End namespace llvm. 231 232 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H 233