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 27namespace llvm { 28namespace 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. 36class OrcGenericABI { 37public: 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. 75template <unsigned StubSizeVal> class GenericIndirectStubsInfo { 76public: 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 110private: 111 unsigned NumStubs = 0; 112 sys::OwningMemoryBlock StubsMem; 113}; 114 115class OrcAArch64 { 116public: 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. 150class OrcX86_64_Base { 151public: 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. 176class OrcX86_64_SysV : public OrcX86_64_Base { 177public: 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. 192class OrcX86_64_Win32 : public OrcX86_64_Base { 193public: 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. 208class OrcI386 { 209public: 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. 243class OrcMips32_Base { 244public: 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 270class OrcMips32Le : public OrcMips32_Base { 271public: 272 static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,void *CallbackMgr) 273 { OrcMips32_Base::writeResolverCode(ResolveMem, Reentry, CallbackMgr, false); } 274}; 275 276class OrcMips32Be : public OrcMips32_Base { 277public: 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. 285class OrcMips64 { 286public: 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