OrcABISupport.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // ABI specific code for Orc, e.g. callback assembly.
  15. //
  16. // ABI classes should be part of the JIT *target* process, not the host
  17. // process (except where you're doing hosted JITing and the two are one and the
  18. // same).
  19. //
  20. //===----------------------------------------------------------------------===//
  21. #ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
  22. #define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
  23. #include "llvm/ExecutionEngine/JITSymbol.h"
  24. #include "llvm/Support/Error.h"
  25. #include "llvm/Support/ErrorHandling.h"
  26. #include "llvm/Support/MathExtras.h"
  27. #include <algorithm>
  28. #include <cstdint>
  29. namespace llvm {
  30. namespace orc {
  31. struct IndirectStubsAllocationSizes {
  32. uint64_t StubBytes = 0;
  33. uint64_t PointerBytes = 0;
  34. unsigned NumStubs = 0;
  35. };
  36. template <typename ORCABI>
  37. IndirectStubsAllocationSizes
  38. getIndirectStubsBlockSizes(unsigned MinStubs, unsigned RoundToMultipleOf = 0) {
  39. assert(
  40. (RoundToMultipleOf == 0 || (RoundToMultipleOf % ORCABI::StubSize == 0)) &&
  41. "RoundToMultipleOf is not a multiple of stub size");
  42. uint64_t StubBytes = MinStubs * ORCABI::StubSize;
  43. if (RoundToMultipleOf)
  44. StubBytes = alignTo(StubBytes, RoundToMultipleOf);
  45. unsigned NumStubs = StubBytes / ORCABI::StubSize;
  46. uint64_t PointerBytes = NumStubs * ORCABI::PointerSize;
  47. return {StubBytes, PointerBytes, NumStubs};
  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. static void writeResolverCode(char *ResolveWorkingMem,
  63. JITTargetAddress ResolverTargetAddr,
  64. JITTargetAddress ReentryFnAddr,
  65. JITTargetAddress ReentryCtxAddr) {
  66. llvm_unreachable("writeResolverCode is not supported by the generic host "
  67. "support class");
  68. }
  69. static void writeTrampolines(char *TrampolineBlockWorkingMem,
  70. JITTargetAddress TrampolineBlockTargetAddr,
  71. JITTargetAddress ResolverAddr,
  72. unsigned NumTrampolines) {
  73. llvm_unreachable("writeTrampolines is not supported by the generic host "
  74. "support class");
  75. }
  76. static void writeIndirectStubsBlock(
  77. char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
  78. JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) {
  79. llvm_unreachable(
  80. "writeIndirectStubsBlock is not supported by the generic host "
  81. "support class");
  82. }
  83. };
  84. class OrcAArch64 {
  85. public:
  86. static constexpr unsigned PointerSize = 8;
  87. static constexpr unsigned TrampolineSize = 12;
  88. static constexpr unsigned StubSize = 8;
  89. static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27;
  90. static constexpr unsigned ResolverCodeSize = 0x120;
  91. /// Write the resolver code into the given memory. The user is
  92. /// responsible for allocating the memory and setting permissions.
  93. ///
  94. /// ReentryFnAddr should be the address of a function whose signature matches
  95. /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
  96. /// argument of writeResolverCode will be passed as the second argument to
  97. /// the function at ReentryFnAddr.
  98. static void writeResolverCode(char *ResolverWorkingMem,
  99. JITTargetAddress ResolverTargetAddress,
  100. JITTargetAddress ReentryFnAddr,
  101. JITTargetAddress RentryCtxAddr);
  102. /// Write the requested number of trampolines into the given memory,
  103. /// which must be big enough to hold 1 pointer, plus NumTrampolines
  104. /// trampolines.
  105. static void writeTrampolines(char *TrampolineBlockWorkingMem,
  106. JITTargetAddress TrampolineBlockTargetAddress,
  107. JITTargetAddress ResolverAddr,
  108. unsigned NumTrampolines);
  109. /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
  110. /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
  111. /// Nth stub using the Nth pointer in memory starting at
  112. /// PointersBlockTargetAddress.
  113. static void writeIndirectStubsBlock(
  114. char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
  115. JITTargetAddress PointersBlockTargetAddress, unsigned MinStubs);
  116. };
  117. /// X86_64 code that's common to all ABIs.
  118. ///
  119. /// X86_64 supports lazy JITing.
  120. class OrcX86_64_Base {
  121. public:
  122. static constexpr unsigned PointerSize = 8;
  123. static constexpr unsigned TrampolineSize = 8;
  124. static constexpr unsigned StubSize = 8;
  125. static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
  126. /// Write the requested number of trampolines into the given memory,
  127. /// which must be big enough to hold 1 pointer, plus NumTrampolines
  128. /// trampolines.
  129. static void writeTrampolines(char *TrampolineBlockWorkingMem,
  130. JITTargetAddress TrampolineBlockTargetAddress,
  131. JITTargetAddress ResolverAddr,
  132. unsigned NumTrampolines);
  133. /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
  134. /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
  135. /// Nth stub using the Nth pointer in memory starting at
  136. /// PointersBlockTargetAddress.
  137. static void writeIndirectStubsBlock(
  138. char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
  139. JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
  140. };
  141. /// X86_64 support for SysV ABI (Linux, MacOSX).
  142. ///
  143. /// X86_64_SysV supports lazy JITing.
  144. class OrcX86_64_SysV : public OrcX86_64_Base {
  145. public:
  146. static constexpr unsigned ResolverCodeSize = 0x6C;
  147. /// Write the resolver code into the given memory. The user is
  148. /// responsible for allocating the memory and setting permissions.
  149. ///
  150. /// ReentryFnAddr should be the address of a function whose signature matches
  151. /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
  152. /// argument of writeResolverCode will be passed as the second argument to
  153. /// the function at ReentryFnAddr.
  154. static void writeResolverCode(char *ResolverWorkingMem,
  155. JITTargetAddress ResolverTargetAddress,
  156. JITTargetAddress ReentryFnAddr,
  157. JITTargetAddress ReentryCtxAddr);
  158. };
  159. /// X86_64 support for Win32.
  160. ///
  161. /// X86_64_Win32 supports lazy JITing.
  162. class OrcX86_64_Win32 : public OrcX86_64_Base {
  163. public:
  164. static constexpr unsigned ResolverCodeSize = 0x74;
  165. /// Write the resolver code into the given memory. The user is
  166. /// responsible for allocating the memory and setting permissions.
  167. ///
  168. /// ReentryFnAddr should be the address of a function whose signature matches
  169. /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
  170. /// argument of writeResolverCode will be passed as the second argument to
  171. /// the function at ReentryFnAddr.
  172. static void writeResolverCode(char *ResolverWorkingMem,
  173. JITTargetAddress ResolverTargetAddress,
  174. JITTargetAddress ReentryFnAddr,
  175. JITTargetAddress ReentryCtxAddr);
  176. };
  177. /// I386 support.
  178. ///
  179. /// I386 supports lazy JITing.
  180. class OrcI386 {
  181. public:
  182. static constexpr unsigned PointerSize = 4;
  183. static constexpr unsigned TrampolineSize = 8;
  184. static constexpr unsigned StubSize = 8;
  185. static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
  186. static constexpr unsigned ResolverCodeSize = 0x4a;
  187. /// Write the resolver code into the given memory. The user is
  188. /// responsible for allocating the memory and setting permissions.
  189. ///
  190. /// ReentryFnAddr should be the address of a function whose signature matches
  191. /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
  192. /// argument of writeResolverCode will be passed as the second argument to
  193. /// the function at ReentryFnAddr.
  194. static void writeResolverCode(char *ResolverWorkingMem,
  195. JITTargetAddress ResolverTargetAddress,
  196. JITTargetAddress ReentryFnAddr,
  197. JITTargetAddress ReentryCtxAddr);
  198. /// Write the requested number of trampolines into the given memory,
  199. /// which must be big enough to hold 1 pointer, plus NumTrampolines
  200. /// trampolines.
  201. static void writeTrampolines(char *TrampolineBlockWorkingMem,
  202. JITTargetAddress TrampolineBlockTargetAddress,
  203. JITTargetAddress ResolverAddr,
  204. unsigned NumTrampolines);
  205. /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
  206. /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
  207. /// Nth stub using the Nth pointer in memory starting at
  208. /// PointersBlockTargetAddress.
  209. static void writeIndirectStubsBlock(
  210. char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
  211. JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
  212. };
  213. // @brief Mips32 support.
  214. //
  215. // Mips32 supports lazy JITing.
  216. class OrcMips32_Base {
  217. public:
  218. static constexpr unsigned PointerSize = 4;
  219. static constexpr unsigned TrampolineSize = 20;
  220. static constexpr unsigned StubSize = 8;
  221. static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
  222. static constexpr unsigned ResolverCodeSize = 0xfc;
  223. /// Write the requested number of trampolines into the given memory,
  224. /// which must be big enough to hold 1 pointer, plus NumTrampolines
  225. /// trampolines.
  226. static void writeTrampolines(char *TrampolineBlockWorkingMem,
  227. JITTargetAddress TrampolineBlockTargetAddress,
  228. JITTargetAddress ResolverAddr,
  229. unsigned NumTrampolines);
  230. /// Write the resolver code into the given memory. The user is
  231. /// responsible for allocating the memory and setting permissions.
  232. ///
  233. /// ReentryFnAddr should be the address of a function whose signature matches
  234. /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
  235. /// argument of writeResolverCode will be passed as the second argument to
  236. /// the function at ReentryFnAddr.
  237. static void writeResolverCode(char *ResolverBlockWorkingMem,
  238. JITTargetAddress ResolverBlockTargetAddress,
  239. JITTargetAddress ReentryFnAddr,
  240. JITTargetAddress ReentryCtxAddr,
  241. bool isBigEndian);
  242. /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
  243. /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
  244. /// Nth stub using the Nth pointer in memory starting at
  245. /// PointersBlockTargetAddress.
  246. static void writeIndirectStubsBlock(
  247. char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
  248. JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
  249. };
  250. class OrcMips32Le : public OrcMips32_Base {
  251. public:
  252. static void writeResolverCode(char *ResolverWorkingMem,
  253. JITTargetAddress ResolverTargetAddress,
  254. JITTargetAddress ReentryFnAddr,
  255. JITTargetAddress ReentryCtxAddr) {
  256. OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
  257. ReentryFnAddr, ReentryCtxAddr, false);
  258. }
  259. };
  260. class OrcMips32Be : public OrcMips32_Base {
  261. public:
  262. static void writeResolverCode(char *ResolverWorkingMem,
  263. JITTargetAddress ResolverTargetAddress,
  264. JITTargetAddress ReentryFnAddr,
  265. JITTargetAddress ReentryCtxAddr) {
  266. OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
  267. ReentryFnAddr, ReentryCtxAddr, true);
  268. }
  269. };
  270. // @brief Mips64 support.
  271. //
  272. // Mips64 supports lazy JITing.
  273. class OrcMips64 {
  274. public:
  275. static constexpr unsigned PointerSize = 8;
  276. static constexpr unsigned TrampolineSize = 40;
  277. static constexpr unsigned StubSize = 32;
  278. static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
  279. static constexpr unsigned ResolverCodeSize = 0x120;
  280. /// Write the resolver code into the given memory. The user is
  281. /// responsible for allocating the memory and setting permissions.
  282. ///
  283. /// ReentryFnAddr should be the address of a function whose signature matches
  284. /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
  285. /// argument of writeResolverCode will be passed as the second argument to
  286. /// the function at ReentryFnAddr.
  287. static void writeResolverCode(char *ResolverWorkingMem,
  288. JITTargetAddress ResolverTargetAddress,
  289. JITTargetAddress ReentryFnAddr,
  290. JITTargetAddress ReentryCtxAddr);
  291. /// Write the requested number of trampolines into the given memory,
  292. /// which must be big enough to hold 1 pointer, plus NumTrampolines
  293. /// trampolines.
  294. static void writeTrampolines(char *TrampolineBlockWorkingMem,
  295. JITTargetAddress TrampolineBlockTargetAddress,
  296. JITTargetAddress ResolverFnAddr,
  297. unsigned NumTrampolines);
  298. /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
  299. /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
  300. /// Nth stub using the Nth pointer in memory starting at
  301. /// PointersBlockTargetAddress.
  302. static void writeIndirectStubsBlock(
  303. char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress,
  304. JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs);
  305. };
  306. } // end namespace orc
  307. } // end namespace llvm
  308. #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
  309. #ifdef __GNUC__
  310. #pragma GCC diagnostic pop
  311. #endif