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