Home | History | Annotate | Line # | Download | only in Orc
      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 } // end namespace orc
    334 } // end namespace llvm
    335 
    336 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
    337