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