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/MathExtras.h" 24 #include <cstdint> 25 26 namespace llvm { 27 namespace orc { 28 29 struct IndirectStubsAllocationSizes { 30 uint64_t StubBytes = 0; 31 uint64_t PointerBytes = 0; 32 unsigned NumStubs = 0; 33 }; 34 35 template <typename ORCABI> 36 IndirectStubsAllocationSizes 37 getIndirectStubsBlockSizes(unsigned MinStubs, unsigned RoundToMultipleOf = 0) { 38 assert( 39 (RoundToMultipleOf == 0 || (RoundToMultipleOf % ORCABI::StubSize == 0)) && 40 "RoundToMultipleOf is not a multiple of stub size"); 41 uint64_t StubBytes = MinStubs * ORCABI::StubSize; 42 if (RoundToMultipleOf) 43 StubBytes = alignTo(StubBytes, RoundToMultipleOf); 44 unsigned NumStubs = StubBytes / ORCABI::StubSize; 45 uint64_t PointerBytes = NumStubs * ORCABI::PointerSize; 46 return {StubBytes, PointerBytes, NumStubs}; 47 } 48 49 /// Generic ORC ABI support. 50 /// 51 /// This class can be substituted as the target architecture support class for 52 /// ORC templates that require one (e.g. IndirectStubsManagers). It does not 53 /// support lazy JITing however, and any attempt to use that functionality 54 /// will result in execution of an llvm_unreachable. 55 class OrcGenericABI { 56 public: 57 static constexpr unsigned PointerSize = sizeof(uintptr_t); 58 static constexpr unsigned TrampolineSize = 1; 59 static constexpr unsigned StubSize = 1; 60 static constexpr unsigned StubToPointerMaxDisplacement = 1; 61 static constexpr unsigned ResolverCodeSize = 1; 62 63 static void writeResolverCode(char *ResolveWorkingMem, 64 JITTargetAddress ResolverTargetAddr, 65 JITTargetAddress ReentryFnAddr, 66 JITTargetAddress ReentryCtxAddr) { 67 llvm_unreachable("writeResolverCode is not supported by the generic host " 68 "support class"); 69 } 70 71 static void writeTrampolines(char *TrampolineBlockWorkingMem, 72 JITTargetAddress TrampolineBlockTargetAddr, 73 JITTargetAddress ResolverAddr, 74 unsigned NumTrampolines) { 75 llvm_unreachable("writeTrampolines is not supported by the generic host " 76 "support class"); 77 } 78 79 static void writeIndirectStubsBlock( 80 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 81 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) { 82 llvm_unreachable( 83 "writeIndirectStubsBlock is not supported by the generic host " 84 "support class"); 85 } 86 }; 87 88 class OrcAArch64 { 89 public: 90 static constexpr unsigned PointerSize = 8; 91 static constexpr unsigned TrampolineSize = 12; 92 static constexpr unsigned StubSize = 8; 93 static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27; 94 static constexpr unsigned ResolverCodeSize = 0x120; 95 96 /// Write the resolver code into the given memory. The user is 97 /// responsible for allocating the memory and setting permissions. 98 /// 99 /// ReentryFnAddr should be the address of a function whose signature matches 100 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 101 /// argument of writeResolverCode will be passed as the second argument to 102 /// the function at ReentryFnAddr. 103 static void writeResolverCode(char *ResolverWorkingMem, 104 JITTargetAddress ResolverTargetAddress, 105 JITTargetAddress ReentryFnAddr, 106 JITTargetAddress RentryCtxAddr); 107 108 /// Write the requested number of trampolines into the given memory, 109 /// which must be big enough to hold 1 pointer, plus NumTrampolines 110 /// trampolines. 111 static void writeTrampolines(char *TrampolineBlockWorkingMem, 112 JITTargetAddress TrampolineBlockTargetAddress, 113 JITTargetAddress ResolverAddr, 114 unsigned NumTrampolines); 115 116 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 117 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 118 /// Nth stub using the Nth pointer in memory starting at 119 /// PointersBlockTargetAddress. 120 static void writeIndirectStubsBlock( 121 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 122 JITTargetAddress PointersBlockTargetAddress, unsigned MinStubs); 123 }; 124 125 /// X86_64 code that's common to all ABIs. 126 /// 127 /// X86_64 supports lazy JITing. 128 class OrcX86_64_Base { 129 public: 130 static constexpr unsigned PointerSize = 8; 131 static constexpr unsigned TrampolineSize = 8; 132 static constexpr unsigned StubSize = 8; 133 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 134 135 /// Write the requested number of trampolines into the given memory, 136 /// which must be big enough to hold 1 pointer, plus NumTrampolines 137 /// trampolines. 138 static void writeTrampolines(char *TrampolineBlockWorkingMem, 139 JITTargetAddress TrampolineBlockTargetAddress, 140 JITTargetAddress ResolverAddr, 141 unsigned NumTrampolines); 142 143 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 144 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 145 /// Nth stub using the Nth pointer in memory starting at 146 /// PointersBlockTargetAddress. 147 static void writeIndirectStubsBlock( 148 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 149 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); 150 }; 151 152 /// X86_64 support for SysV ABI (Linux, MacOSX). 153 /// 154 /// X86_64_SysV supports lazy JITing. 155 class OrcX86_64_SysV : public OrcX86_64_Base { 156 public: 157 static constexpr unsigned ResolverCodeSize = 0x6C; 158 159 /// Write the resolver code into the given memory. The user is 160 /// responsible for allocating the memory and setting permissions. 161 /// 162 /// ReentryFnAddr should be the address of a function whose signature matches 163 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 164 /// argument of writeResolverCode will be passed as the second argument to 165 /// the function at ReentryFnAddr. 166 static void writeResolverCode(char *ResolverWorkingMem, 167 JITTargetAddress ResolverTargetAddress, 168 JITTargetAddress ReentryFnAddr, 169 JITTargetAddress ReentryCtxAddr); 170 }; 171 172 /// X86_64 support for Win32. 173 /// 174 /// X86_64_Win32 supports lazy JITing. 175 class OrcX86_64_Win32 : public OrcX86_64_Base { 176 public: 177 static constexpr unsigned ResolverCodeSize = 0x74; 178 179 /// Write the resolver code into the given memory. The user is 180 /// responsible for allocating the memory and setting permissions. 181 /// 182 /// ReentryFnAddr should be the address of a function whose signature matches 183 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 184 /// argument of writeResolverCode will be passed as the second argument to 185 /// the function at ReentryFnAddr. 186 static void writeResolverCode(char *ResolverWorkingMem, 187 JITTargetAddress ResolverTargetAddress, 188 JITTargetAddress ReentryFnAddr, 189 JITTargetAddress ReentryCtxAddr); 190 }; 191 192 /// I386 support. 193 /// 194 /// I386 supports lazy JITing. 195 class OrcI386 { 196 public: 197 static constexpr unsigned PointerSize = 4; 198 static constexpr unsigned TrampolineSize = 8; 199 static constexpr unsigned StubSize = 8; 200 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 201 static constexpr unsigned ResolverCodeSize = 0x4a; 202 203 /// Write the resolver code into the given memory. The user is 204 /// responsible for allocating the memory and setting permissions. 205 /// 206 /// ReentryFnAddr should be the address of a function whose signature matches 207 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 208 /// argument of writeResolverCode will be passed as the second argument to 209 /// the function at ReentryFnAddr. 210 static void writeResolverCode(char *ResolverWorkingMem, 211 JITTargetAddress ResolverTargetAddress, 212 JITTargetAddress ReentryFnAddr, 213 JITTargetAddress ReentryCtxAddr); 214 215 /// Write the requested number of trampolines into the given memory, 216 /// which must be big enough to hold 1 pointer, plus NumTrampolines 217 /// trampolines. 218 static void writeTrampolines(char *TrampolineBlockWorkingMem, 219 JITTargetAddress TrampolineBlockTargetAddress, 220 JITTargetAddress ResolverAddr, 221 unsigned NumTrampolines); 222 223 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 224 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 225 /// Nth stub using the Nth pointer in memory starting at 226 /// PointersBlockTargetAddress. 227 static void writeIndirectStubsBlock( 228 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 229 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); 230 }; 231 232 // @brief Mips32 support. 233 // 234 // Mips32 supports lazy JITing. 235 class OrcMips32_Base { 236 public: 237 static constexpr unsigned PointerSize = 4; 238 static constexpr unsigned TrampolineSize = 20; 239 static constexpr unsigned StubSize = 8; 240 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 241 static constexpr unsigned ResolverCodeSize = 0xfc; 242 243 /// Write the requested number of trampolines into the given memory, 244 /// which must be big enough to hold 1 pointer, plus NumTrampolines 245 /// trampolines. 246 static void writeTrampolines(char *TrampolineBlockWorkingMem, 247 JITTargetAddress TrampolineBlockTargetAddress, 248 JITTargetAddress ResolverAddr, 249 unsigned NumTrampolines); 250 251 /// Write the resolver code into the given memory. The user is 252 /// responsible for allocating the memory and setting permissions. 253 /// 254 /// ReentryFnAddr should be the address of a function whose signature matches 255 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 256 /// argument of writeResolverCode will be passed as the second argument to 257 /// the function at ReentryFnAddr. 258 static void writeResolverCode(char *ResolverBlockWorkingMem, 259 JITTargetAddress ResolverBlockTargetAddress, 260 JITTargetAddress ReentryFnAddr, 261 JITTargetAddress ReentryCtxAddr, 262 bool isBigEndian); 263 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 264 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 265 /// Nth stub using the Nth pointer in memory starting at 266 /// PointersBlockTargetAddress. 267 static void writeIndirectStubsBlock( 268 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 269 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); 270 }; 271 272 class OrcMips32Le : public OrcMips32_Base { 273 public: 274 static void writeResolverCode(char *ResolverWorkingMem, 275 JITTargetAddress ResolverTargetAddress, 276 JITTargetAddress ReentryFnAddr, 277 JITTargetAddress ReentryCtxAddr) { 278 OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress, 279 ReentryFnAddr, ReentryCtxAddr, false); 280 } 281 }; 282 283 class OrcMips32Be : public OrcMips32_Base { 284 public: 285 static void writeResolverCode(char *ResolverWorkingMem, 286 JITTargetAddress ResolverTargetAddress, 287 JITTargetAddress ReentryFnAddr, 288 JITTargetAddress ReentryCtxAddr) { 289 OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress, 290 ReentryFnAddr, ReentryCtxAddr, true); 291 } 292 }; 293 294 // @brief Mips64 support. 295 // 296 // Mips64 supports lazy JITing. 297 class OrcMips64 { 298 public: 299 static constexpr unsigned PointerSize = 8; 300 static constexpr unsigned TrampolineSize = 40; 301 static constexpr unsigned StubSize = 32; 302 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 303 static constexpr unsigned ResolverCodeSize = 0x120; 304 305 /// Write the resolver code into the given memory. The user is 306 /// responsible for allocating the memory and setting permissions. 307 /// 308 /// ReentryFnAddr should be the address of a function whose signature matches 309 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 310 /// argument of writeResolverCode will be passed as the second argument to 311 /// the function at ReentryFnAddr. 312 static void writeResolverCode(char *ResolverWorkingMem, 313 JITTargetAddress ResolverTargetAddress, 314 JITTargetAddress ReentryFnAddr, 315 JITTargetAddress ReentryCtxAddr); 316 317 /// Write the requested number of trampolines into the given memory, 318 /// which must be big enough to hold 1 pointer, plus NumTrampolines 319 /// trampolines. 320 static void writeTrampolines(char *TrampolineBlockWorkingMem, 321 JITTargetAddress TrampolineBlockTargetAddress, 322 JITTargetAddress ResolverFnAddr, 323 unsigned NumTrampolines); 324 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 325 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 326 /// Nth stub using the Nth pointer in memory starting at 327 /// PointersBlockTargetAddress. 328 static void writeIndirectStubsBlock( 329 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 330 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); 331 }; 332 333 // @brief riscv64 support. 334 // 335 // RISC-V 64 supports lazy JITing. 336 class OrcRiscv64 { 337 public: 338 static constexpr unsigned PointerSize = 8; 339 static constexpr unsigned TrampolineSize = 16; 340 static constexpr unsigned StubSize = 16; 341 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 342 static constexpr unsigned ResolverCodeSize = 0x148; 343 344 /// Write the resolver code into the given memory. The user is 345 /// responsible for allocating the memory and setting permissions. 346 /// 347 /// ReentryFnAddr should be the address of a function whose signature matches 348 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 349 /// argument of writeResolverCode will be passed as the second argument to 350 /// the function at ReentryFnAddr. 351 static void writeResolverCode(char *ResolverWorkingMem, 352 JITTargetAddress ResolverTargetAddress, 353 JITTargetAddress ReentryFnAddr, 354 JITTargetAddress ReentryCtxAddr); 355 356 /// Write the requested number of trampolines into the given memory, 357 /// which must be big enough to hold 1 pointer, plus NumTrampolines 358 /// trampolines. 359 static void writeTrampolines(char *TrampolineBlockWorkingMem, 360 JITTargetAddress TrampolineBlockTargetAddress, 361 JITTargetAddress ResolverFnAddr, 362 unsigned NumTrampolines); 363 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 364 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 365 /// Nth stub using the Nth pointer in memory starting at 366 /// PointersBlockTargetAddress. 367 static void writeIndirectStubsBlock( 368 char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, 369 JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); 370 }; 371 372 } // end namespace orc 373 } // end namespace llvm 374 375 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H 376