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/Orc/Shared/ExecutorAddress.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 ExecutorAddr ResolverTargetAddr, 65 ExecutorAddr ReentryFnAddr, 66 ExecutorAddr ReentryCtxAddr) { 67 llvm_unreachable("writeResolverCode is not supported by the generic host " 68 "support class"); 69 } 70 71 static void writeTrampolines(char *TrampolineBlockWorkingMem, 72 ExecutorAddr TrampolineBlockTargetAddr, 73 ExecutorAddr ResolverAddr, 74 unsigned NumTrampolines) { 75 llvm_unreachable("writeTrampolines is not supported by the generic host " 76 "support class"); 77 } 78 79 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 80 ExecutorAddr StubsBlockTargetAddress, 81 ExecutorAddr PointersBlockTargetAddress, 82 unsigned NumStubs) { 83 llvm_unreachable( 84 "writeIndirectStubsBlock is not supported by the generic host " 85 "support class"); 86 } 87 }; 88 89 class OrcAArch64 { 90 public: 91 static constexpr unsigned PointerSize = 8; 92 static constexpr unsigned TrampolineSize = 12; 93 static constexpr unsigned StubSize = 8; 94 static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27; 95 static constexpr unsigned ResolverCodeSize = 0x120; 96 97 /// Write the resolver code into the given memory. The user is 98 /// responsible for allocating the memory and setting permissions. 99 /// 100 /// ReentryFnAddr should be the address of a function whose signature matches 101 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 102 /// argument of writeResolverCode will be passed as the second argument to 103 /// the function at ReentryFnAddr. 104 static void writeResolverCode(char *ResolverWorkingMem, 105 ExecutorAddr ResolverTargetAddress, 106 ExecutorAddr ReentryFnAddr, 107 ExecutorAddr RentryCtxAddr); 108 109 /// Write the requested number of trampolines into the given memory, 110 /// which must be big enough to hold 1 pointer, plus NumTrampolines 111 /// trampolines. 112 static void writeTrampolines(char *TrampolineBlockWorkingMem, 113 ExecutorAddr TrampolineBlockTargetAddress, 114 ExecutorAddr ResolverAddr, 115 unsigned NumTrampolines); 116 117 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 118 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 119 /// Nth stub using the Nth pointer in memory starting at 120 /// PointersBlockTargetAddress. 121 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 122 ExecutorAddr StubsBlockTargetAddress, 123 ExecutorAddr PointersBlockTargetAddress, 124 unsigned MinStubs); 125 }; 126 127 /// X86_64 code that's common to all ABIs. 128 /// 129 /// X86_64 supports lazy JITing. 130 class OrcX86_64_Base { 131 public: 132 static constexpr unsigned PointerSize = 8; 133 static constexpr unsigned TrampolineSize = 8; 134 static constexpr unsigned StubSize = 8; 135 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 136 137 /// Write the requested number of trampolines into the given memory, 138 /// which must be big enough to hold 1 pointer, plus NumTrampolines 139 /// trampolines. 140 static void writeTrampolines(char *TrampolineBlockWorkingMem, 141 ExecutorAddr TrampolineBlockTargetAddress, 142 ExecutorAddr ResolverAddr, 143 unsigned NumTrampolines); 144 145 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 146 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 147 /// Nth stub using the Nth pointer in memory starting at 148 /// PointersBlockTargetAddress. 149 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 150 ExecutorAddr StubsBlockTargetAddress, 151 ExecutorAddr PointersBlockTargetAddress, 152 unsigned NumStubs); 153 }; 154 155 /// X86_64 support for SysV ABI (Linux, MacOSX). 156 /// 157 /// X86_64_SysV supports lazy JITing. 158 class OrcX86_64_SysV : public OrcX86_64_Base { 159 public: 160 static constexpr unsigned ResolverCodeSize = 0x6C; 161 162 /// Write the resolver code into the given memory. The user is 163 /// responsible for allocating the memory and setting permissions. 164 /// 165 /// ReentryFnAddr should be the address of a function whose signature matches 166 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 167 /// argument of writeResolverCode will be passed as the second argument to 168 /// the function at ReentryFnAddr. 169 static void writeResolverCode(char *ResolverWorkingMem, 170 ExecutorAddr ResolverTargetAddress, 171 ExecutorAddr ReentryFnAddr, 172 ExecutorAddr ReentryCtxAddr); 173 }; 174 175 /// X86_64 support for Win32. 176 /// 177 /// X86_64_Win32 supports lazy JITing. 178 class OrcX86_64_Win32 : public OrcX86_64_Base { 179 public: 180 static constexpr unsigned ResolverCodeSize = 0x74; 181 182 /// Write the resolver code into the given memory. The user is 183 /// responsible for allocating the memory and setting permissions. 184 /// 185 /// ReentryFnAddr should be the address of a function whose signature matches 186 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 187 /// argument of writeResolverCode will be passed as the second argument to 188 /// the function at ReentryFnAddr. 189 static void writeResolverCode(char *ResolverWorkingMem, 190 ExecutorAddr ResolverTargetAddress, 191 ExecutorAddr ReentryFnAddr, 192 ExecutorAddr ReentryCtxAddr); 193 }; 194 195 /// I386 support. 196 /// 197 /// I386 supports lazy JITing. 198 class OrcI386 { 199 public: 200 static constexpr unsigned PointerSize = 4; 201 static constexpr unsigned TrampolineSize = 8; 202 static constexpr unsigned StubSize = 8; 203 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 204 static constexpr unsigned ResolverCodeSize = 0x4a; 205 206 /// Write the resolver code into the given memory. The user is 207 /// responsible for allocating the memory and setting permissions. 208 /// 209 /// ReentryFnAddr should be the address of a function whose signature matches 210 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 211 /// argument of writeResolverCode will be passed as the second argument to 212 /// the function at ReentryFnAddr. 213 static void writeResolverCode(char *ResolverWorkingMem, 214 ExecutorAddr ResolverTargetAddress, 215 ExecutorAddr ReentryFnAddr, 216 ExecutorAddr ReentryCtxAddr); 217 218 /// Write the requested 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(char *TrampolineBlockWorkingMem, 222 ExecutorAddr TrampolineBlockTargetAddress, 223 ExecutorAddr ResolverAddr, 224 unsigned NumTrampolines); 225 226 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 227 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 228 /// Nth stub using the Nth pointer in memory starting at 229 /// PointersBlockTargetAddress. 230 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 231 ExecutorAddr StubsBlockTargetAddress, 232 ExecutorAddr PointersBlockTargetAddress, 233 unsigned NumStubs); 234 }; 235 236 // @brief Mips32 support. 237 // 238 // Mips32 supports lazy JITing. 239 class OrcMips32_Base { 240 public: 241 static constexpr unsigned PointerSize = 4; 242 static constexpr unsigned TrampolineSize = 20; 243 static constexpr unsigned StubSize = 8; 244 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 245 static constexpr unsigned ResolverCodeSize = 0xfc; 246 247 /// Write the requested number of trampolines into the given memory, 248 /// which must be big enough to hold 1 pointer, plus NumTrampolines 249 /// trampolines. 250 static void writeTrampolines(char *TrampolineBlockWorkingMem, 251 ExecutorAddr TrampolineBlockTargetAddress, 252 ExecutorAddr ResolverAddr, 253 unsigned NumTrampolines); 254 255 /// Write the resolver code into the given memory. The user is 256 /// responsible for allocating the memory and setting permissions. 257 /// 258 /// ReentryFnAddr should be the address of a function whose signature matches 259 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 260 /// argument of writeResolverCode will be passed as the second argument to 261 /// the function at ReentryFnAddr. 262 static void writeResolverCode(char *ResolverBlockWorkingMem, 263 ExecutorAddr ResolverBlockTargetAddress, 264 ExecutorAddr ReentryFnAddr, 265 ExecutorAddr ReentryCtxAddr, bool isBigEndian); 266 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 267 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 268 /// Nth stub using the Nth pointer in memory starting at 269 /// PointersBlockTargetAddress. 270 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 271 ExecutorAddr StubsBlockTargetAddress, 272 ExecutorAddr PointersBlockTargetAddress, 273 unsigned NumStubs); 274 }; 275 276 class OrcMips32Le : public OrcMips32_Base { 277 public: 278 static void writeResolverCode(char *ResolverWorkingMem, 279 ExecutorAddr ResolverTargetAddress, 280 ExecutorAddr ReentryFnAddr, 281 ExecutorAddr ReentryCtxAddr) { 282 OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress, 283 ReentryFnAddr, ReentryCtxAddr, false); 284 } 285 }; 286 287 class OrcMips32Be : public OrcMips32_Base { 288 public: 289 static void writeResolverCode(char *ResolverWorkingMem, 290 ExecutorAddr ResolverTargetAddress, 291 ExecutorAddr ReentryFnAddr, 292 ExecutorAddr ReentryCtxAddr) { 293 OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress, 294 ReentryFnAddr, ReentryCtxAddr, true); 295 } 296 }; 297 298 // @brief Mips64 support. 299 // 300 // Mips64 supports lazy JITing. 301 class OrcMips64 { 302 public: 303 static constexpr unsigned PointerSize = 8; 304 static constexpr unsigned TrampolineSize = 40; 305 static constexpr unsigned StubSize = 32; 306 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 307 static constexpr unsigned ResolverCodeSize = 0x120; 308 309 /// Write the resolver code into the given memory. The user is 310 /// responsible for allocating the memory and setting permissions. 311 /// 312 /// ReentryFnAddr should be the address of a function whose signature matches 313 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 314 /// argument of writeResolverCode will be passed as the second argument to 315 /// the function at ReentryFnAddr. 316 static void writeResolverCode(char *ResolverWorkingMem, 317 ExecutorAddr ResolverTargetAddress, 318 ExecutorAddr ReentryFnAddr, 319 ExecutorAddr ReentryCtxAddr); 320 321 /// Write the requested number of trampolines into the given memory, 322 /// which must be big enough to hold 1 pointer, plus NumTrampolines 323 /// trampolines. 324 static void writeTrampolines(char *TrampolineBlockWorkingMem, 325 ExecutorAddr TrampolineBlockTargetAddress, 326 ExecutorAddr ResolverFnAddr, 327 unsigned NumTrampolines); 328 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 329 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 330 /// Nth stub using the Nth pointer in memory starting at 331 /// PointersBlockTargetAddress. 332 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 333 ExecutorAddr StubsBlockTargetAddress, 334 ExecutorAddr PointersBlockTargetAddress, 335 unsigned NumStubs); 336 }; 337 338 // @brief riscv64 support. 339 // 340 // RISC-V 64 supports lazy JITing. 341 class OrcRiscv64 { 342 public: 343 static constexpr unsigned PointerSize = 8; 344 static constexpr unsigned TrampolineSize = 16; 345 static constexpr unsigned StubSize = 16; 346 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 347 static constexpr unsigned ResolverCodeSize = 0x148; 348 349 /// Write the resolver code into the given memory. The user is 350 /// responsible for allocating the memory and setting permissions. 351 /// 352 /// ReentryFnAddr should be the address of a function whose signature matches 353 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 354 /// argument of writeResolverCode will be passed as the second argument to 355 /// the function at ReentryFnAddr. 356 static void writeResolverCode(char *ResolverWorkingMem, 357 ExecutorAddr ResolverTargetAddress, 358 ExecutorAddr ReentryFnAddr, 359 ExecutorAddr ReentryCtxAddr); 360 361 /// Write the requested number of trampolines into the given memory, 362 /// which must be big enough to hold 1 pointer, plus NumTrampolines 363 /// trampolines. 364 static void writeTrampolines(char *TrampolineBlockWorkingMem, 365 ExecutorAddr TrampolineBlockTargetAddress, 366 ExecutorAddr ResolverFnAddr, 367 unsigned NumTrampolines); 368 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 369 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 370 /// Nth stub using the Nth pointer in memory starting at 371 /// PointersBlockTargetAddress. 372 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 373 ExecutorAddr StubsBlockTargetAddress, 374 ExecutorAddr PointersBlockTargetAddress, 375 unsigned NumStubs); 376 }; 377 378 // @brief loongarch64 support. 379 // 380 // LoongArch 64 supports lazy JITing. 381 class OrcLoongArch64 { 382 public: 383 static constexpr unsigned PointerSize = 8; 384 static constexpr unsigned TrampolineSize = 16; 385 static constexpr unsigned StubSize = 16; 386 static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; 387 static constexpr unsigned ResolverCodeSize = 0xc8; 388 389 /// Write the resolver code into the given memory. The user is 390 /// responsible for allocating the memory and setting permissions. 391 /// 392 /// ReentryFnAddr should be the address of a function whose signature matches 393 /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr 394 /// argument of writeResolverCode will be passed as the second argument to 395 /// the function at ReentryFnAddr. 396 static void writeResolverCode(char *ResolverWorkingMem, 397 ExecutorAddr ResolverTargetAddress, 398 ExecutorAddr ReentryFnAddr, 399 ExecutorAddr ReentryCtxAddr); 400 401 /// Write the requested number of trampolines into the given memory, 402 /// which must be big enough to hold 1 pointer, plus NumTrampolines 403 /// trampolines. 404 static void writeTrampolines(char *TrampolineBlockWorkingMem, 405 ExecutorAddr TrampolineBlockTargetAddress, 406 ExecutorAddr ResolverFnAddr, 407 unsigned NumTrampolines); 408 409 /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. 410 /// Stubs will be written as if linked at StubsBlockTargetAddress, with the 411 /// Nth stub using the Nth pointer in memory starting at 412 /// PointersBlockTargetAddress. 413 static void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 414 ExecutorAddr StubsBlockTargetAddress, 415 ExecutorAddr PointersBlockTargetAddress, 416 unsigned NumStubs); 417 }; 418 419 } // end namespace orc 420 } // end namespace llvm 421 422 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H 423