asmjit 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/asmjit.gemspec +1 -1
  4. data/ext/asmjit/asmjit/.editorconfig +10 -0
  5. data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
  6. data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
  7. data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
  8. data/ext/asmjit/asmjit/.gitignore +6 -0
  9. data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
  10. data/ext/asmjit/asmjit/LICENSE.md +17 -0
  11. data/ext/asmjit/asmjit/README.md +69 -0
  12. data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
  13. data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
  14. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
  15. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
  16. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
  17. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
  18. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
  19. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
  20. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
  21. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
  22. data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
  23. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
  24. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
  25. data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
  26. data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
  27. data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
  28. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
  29. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
  30. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
  31. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
  32. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
  33. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
  34. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
  35. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
  36. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
  37. data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
  38. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
  39. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
  40. data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
  41. data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
  42. data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
  43. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
  44. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
  45. data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
  46. data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
  47. data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
  48. data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
  49. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
  50. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
  51. data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
  52. data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
  53. data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
  54. data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
  55. data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
  56. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
  57. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
  58. data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
  59. data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
  60. data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
  61. data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
  62. data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
  63. data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
  64. data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
  65. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
  66. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
  67. data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
  68. data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
  69. data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
  70. data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
  71. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
  72. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
  73. data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
  74. data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
  75. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
  76. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
  77. data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
  78. data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
  79. data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
  80. data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
  81. data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
  82. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
  83. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
  84. data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
  85. data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
  86. data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
  87. data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
  88. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
  89. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
  90. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
  91. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
  92. data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
  93. data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
  94. data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
  95. data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
  96. data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
  97. data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
  98. data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
  99. data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
  100. data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
  101. data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
  102. data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
  103. data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
  104. data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
  105. data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
  106. data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
  107. data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
  108. data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
  109. data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
  110. data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
  111. data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
  112. data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
  113. data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
  114. data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
  115. data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
  116. data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
  117. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
  118. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
  119. data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
  120. data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
  121. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
  122. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
  123. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
  124. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
  125. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
  126. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
  127. data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
  128. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
  129. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
  130. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
  131. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
  132. data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
  133. data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
  134. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
  135. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
  136. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
  137. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
  138. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
  139. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
  140. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
  141. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
  142. data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
  143. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
  144. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
  145. data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
  146. data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
  147. data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
  148. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
  149. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
  150. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
  151. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
  152. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
  153. data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
  154. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
  155. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
  156. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
  157. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
  158. data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
  159. data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
  160. data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
  161. data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
  162. data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
  163. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
  164. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
  165. data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
  166. data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
  167. data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
  168. data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
  169. data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
  170. data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
  171. data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
  172. data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
  173. data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
  174. data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
  175. data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
  176. data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
  177. data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
  178. data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
  179. data/ext/asmjit/asmjit/test/broken.cpp +312 -0
  180. data/ext/asmjit/asmjit/test/broken.h +148 -0
  181. data/ext/asmjit/asmjit/test/cmdline.h +61 -0
  182. data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
  183. data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
  184. data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
  185. data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
  186. data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
  187. data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
  188. data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
  189. data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
  190. data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
  191. data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
  192. data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
  193. data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
  194. data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
  195. data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
  196. data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
  197. data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
  198. data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
  199. data/ext/asmjit/asmjit.cc +18 -0
  200. data/lib/asmjit/version.rb +1 -1
  201. metadata +197 -2
@@ -0,0 +1,1035 @@
1
+ // This file is part of AsmJit project <https://asmjit.com>
2
+ //
3
+ // See asmjit.h or LICENSE.md for license and copyright information
4
+ // SPDX-License-Identifier: Zlib
5
+
6
+ #ifndef ASMJIT_CORE_CODEHOLDER_H_INCLUDED
7
+ #define ASMJIT_CORE_CODEHOLDER_H_INCLUDED
8
+
9
+ #include "../core/archtraits.h"
10
+ #include "../core/codebuffer.h"
11
+ #include "../core/errorhandler.h"
12
+ #include "../core/operand.h"
13
+ #include "../core/string.h"
14
+ #include "../core/support.h"
15
+ #include "../core/target.h"
16
+ #include "../core/zone.h"
17
+ #include "../core/zonehash.h"
18
+ #include "../core/zonestring.h"
19
+ #include "../core/zonetree.h"
20
+ #include "../core/zonevector.h"
21
+
22
+ ASMJIT_BEGIN_NAMESPACE
23
+
24
+ //! \addtogroup asmjit_core
25
+ //! \{
26
+
27
+ class BaseEmitter;
28
+ class CodeHolder;
29
+ class LabelEntry;
30
+ class Logger;
31
+
32
+ //! Operator type that can be used within an \ref Expression.
33
+ enum class ExpressionOpType : uint8_t {
34
+ //! Addition.
35
+ kAdd = 0,
36
+ //! Subtraction.
37
+ kSub = 1,
38
+ //! Multiplication
39
+ kMul = 2,
40
+ //! Logical left shift.
41
+ kSll = 3,
42
+ //! Logical right shift.
43
+ kSrl = 4,
44
+ //! Arithmetic right shift.
45
+ kSra = 5
46
+ };
47
+
48
+ //! Value tyoe that can be used within an \ref Expression.
49
+ enum class ExpressionValueType : uint8_t {
50
+ //! No value or invalid.
51
+ kNone = 0,
52
+ //! Value is 64-bit unsigned integer (constant).
53
+ kConstant = 1,
54
+ //! Value is \ref LabelEntry, which references a \ref Label.
55
+ kLabel = 2,
56
+ //! Value is \ref Expression
57
+ kExpression = 3
58
+ };
59
+
60
+ //! Expression node that can reference constants, labels, and another expressions.
61
+ struct Expression {
62
+ //! Expression value.
63
+ union Value {
64
+ //! Constant.
65
+ uint64_t constant;
66
+ //! Pointer to another expression.
67
+ Expression* expression;
68
+ //! Pointer to \ref LabelEntry.
69
+ LabelEntry* label;
70
+ };
71
+
72
+ //! \name Members
73
+ //! \{
74
+
75
+ //! Operation type.
76
+ ExpressionOpType opType;
77
+ //! Value types of \ref value.
78
+ ExpressionValueType valueType[2];
79
+ //! Reserved for future use, should be initialized to zero.
80
+ uint8_t reserved[5];
81
+ //! Expression left and right values.
82
+ Value value[2];
83
+
84
+ //! \}
85
+
86
+ //! \name Accessors
87
+ //! \{
88
+
89
+ //! Resets the whole expression.
90
+ //!
91
+ //! Changes both values to \ref ExpressionValueType::kNone.
92
+ inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
93
+
94
+ //! Sets the value type at `index` to \ref ExpressionValueType::kConstant and its content to `constant`.
95
+ inline void setValueAsConstant(size_t index, uint64_t constant) noexcept {
96
+ valueType[index] = ExpressionValueType::kConstant;
97
+ value[index].constant = constant;
98
+ }
99
+
100
+ //! Sets the value type at `index` to \ref ExpressionValueType::kLabel and its content to `labelEntry`.
101
+ inline void setValueAsLabel(size_t index, LabelEntry* labelEntry) noexcept {
102
+ valueType[index] = ExpressionValueType::kLabel;
103
+ value[index].label = labelEntry;
104
+ }
105
+
106
+ //! Sets the value type at `index` to \ref ExpressionValueType::kExpression and its content to `expression`.
107
+ inline void setValueAsExpression(size_t index, Expression* expression) noexcept {
108
+ valueType[index] = ExpressionValueType::kExpression;
109
+ value[index].expression = expression;
110
+ }
111
+
112
+ //! \}
113
+ };
114
+
115
+ //! Section flags, used by \ref Section.
116
+ enum class SectionFlags : uint32_t {
117
+ //! No flags.
118
+ kNone = 0,
119
+ //! Executable (.text sections).
120
+ kExecutable = 0x00000001u,
121
+ //! Read-only (.text and .data sections).
122
+ kReadOnly = 0x00000002u,
123
+ //! Zero initialized by the loader (BSS).
124
+ kZeroInitialized = 0x00000004u,
125
+ //! Info / comment flag.
126
+ kComment = 0x00000008u,
127
+ //! Section created implicitly, can be deleted by \ref Target.
128
+ kImplicit = 0x80000000u
129
+ };
130
+ ASMJIT_DEFINE_ENUM_FLAGS(SectionFlags)
131
+
132
+ //! Flags that can be used with \ref CodeHolder::copySectionData() and \ref CodeHolder::copyFlattenedData().
133
+ enum class CopySectionFlags : uint32_t {
134
+ //! No flags.
135
+ kNone = 0,
136
+
137
+ //! If virtual size of a section is greater than the size of its \ref CodeBuffer then all bytes between the buffer
138
+ //! size and virtual size will be zeroed. If this option is not set then those bytes would be left as is, which
139
+ //! means that if the user didn't initialize them they would have a previous content, which may be unwanted.
140
+ kPadSectionBuffer = 0x00000001u,
141
+
142
+ //! Clears the target buffer if the flattened data is less than the destination size. This option works
143
+ //! only with \ref CodeHolder::copyFlattenedData() as it processes multiple sections. It is ignored by
144
+ //! \ref CodeHolder::copySectionData().
145
+ kPadTargetBuffer = 0x00000002u
146
+ };
147
+ ASMJIT_DEFINE_ENUM_FLAGS(CopySectionFlags)
148
+
149
+ //! Section entry.
150
+ class Section {
151
+ public:
152
+ //! \name Members
153
+ //! \{
154
+
155
+ //! Section id.
156
+ uint32_t _id;
157
+ //! Section flags.
158
+ SectionFlags _flags;
159
+ //! Section alignment requirements (0 if no requirements).
160
+ uint32_t _alignment;
161
+ //! Order (lower value means higher priority).
162
+ int32_t _order;
163
+ //! Offset of this section from base-address.
164
+ uint64_t _offset;
165
+ //! Virtual size of the section (zero initialized sections).
166
+ uint64_t _virtualSize;
167
+ //! Section name (max 35 characters, PE allows max 8).
168
+ FixedString<Globals::kMaxSectionNameSize + 1> _name;
169
+ //! Code or data buffer.
170
+ CodeBuffer _buffer;
171
+
172
+ //! \}
173
+
174
+ //! \name Accessors
175
+ //! \{
176
+
177
+ //! Returns the section id.
178
+ inline uint32_t id() const noexcept { return _id; }
179
+ //! Returns the section name, as a null terminated string.
180
+ inline const char* name() const noexcept { return _name.str; }
181
+
182
+ //! Returns the section data.
183
+ inline uint8_t* data() noexcept { return _buffer.data(); }
184
+ //! \overload
185
+ inline const uint8_t* data() const noexcept { return _buffer.data(); }
186
+
187
+ //! Returns the section flags.
188
+ inline SectionFlags flags() const noexcept { return _flags; }
189
+ //! Tests whether the section has the given `flag`.
190
+ inline bool hasFlag(SectionFlags flag) const noexcept { return Support::test(_flags, flag); }
191
+ //! Adds `flags` to the section flags.
192
+ inline void addFlags(SectionFlags flags) noexcept { _flags |= flags; }
193
+ //! Removes `flags` from the section flags.
194
+ inline void clearFlags(SectionFlags flags) noexcept { _flags &= ~flags; }
195
+
196
+ //! Returns the minimum section alignment
197
+ inline uint32_t alignment() const noexcept { return _alignment; }
198
+ //! Sets the minimum section alignment
199
+ inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
200
+
201
+ //! Returns the section order, which has a higher priority than section id.
202
+ inline int32_t order() const noexcept { return _order; }
203
+
204
+ //! Returns the section offset, relative to base.
205
+ inline uint64_t offset() const noexcept { return _offset; }
206
+ //! Set the section offset.
207
+ inline void setOffset(uint64_t offset) noexcept { _offset = offset; }
208
+
209
+ //! Returns the virtual size of the section.
210
+ //!
211
+ //! Virtual size is initially zero and is never changed by AsmJit. It's normal if virtual size is smaller than
212
+ //! size returned by `bufferSize()` as the buffer stores real data emitted by assemblers or appended by users.
213
+ //!
214
+ //! Use `realSize()` to get the real and final size of this section.
215
+ inline uint64_t virtualSize() const noexcept { return _virtualSize; }
216
+ //! Sets the virtual size of the section.
217
+ inline void setVirtualSize(uint64_t virtualSize) noexcept { _virtualSize = virtualSize; }
218
+
219
+ //! Returns the buffer size of the section.
220
+ inline size_t bufferSize() const noexcept { return _buffer.size(); }
221
+ //! Returns the real size of the section calculated from virtual and buffer sizes.
222
+ inline uint64_t realSize() const noexcept { return Support::max<uint64_t>(virtualSize(), bufferSize()); }
223
+
224
+ //! Returns the `CodeBuffer` used by this section.
225
+ inline CodeBuffer& buffer() noexcept { return _buffer; }
226
+ //! Returns the `CodeBuffer` used by this section (const).
227
+ inline const CodeBuffer& buffer() const noexcept { return _buffer; }
228
+
229
+ //! \}
230
+ };
231
+
232
+ //! Entry in an address table.
233
+ class AddressTableEntry : public ZoneTreeNodeT<AddressTableEntry> {
234
+ public:
235
+ ASMJIT_NONCOPYABLE(AddressTableEntry)
236
+
237
+ //! \name Members
238
+ //! \{
239
+
240
+ //! Address.
241
+ uint64_t _address;
242
+ //! Slot.
243
+ uint32_t _slot;
244
+
245
+ //! \}
246
+
247
+ //! \name Construction & Destruction
248
+ //! \{
249
+
250
+ inline explicit AddressTableEntry(uint64_t address) noexcept
251
+ : _address(address),
252
+ _slot(0xFFFFFFFFu) {}
253
+
254
+ //! \}
255
+
256
+ //! \name Accessors
257
+ //! \{
258
+
259
+ inline uint64_t address() const noexcept { return _address; }
260
+ inline uint32_t slot() const noexcept { return _slot; }
261
+
262
+ inline bool hasAssignedSlot() const noexcept { return _slot != 0xFFFFFFFFu; }
263
+
264
+ inline bool operator<(const AddressTableEntry& other) const noexcept { return _address < other._address; }
265
+ inline bool operator>(const AddressTableEntry& other) const noexcept { return _address > other._address; }
266
+
267
+ inline bool operator<(uint64_t queryAddress) const noexcept { return _address < queryAddress; }
268
+ inline bool operator>(uint64_t queryAddress) const noexcept { return _address > queryAddress; }
269
+
270
+ //! \}
271
+ };
272
+
273
+ //! Offset format type, used by \ref OffsetFormat.
274
+ enum class OffsetType : uint8_t {
275
+ //! A value having `_immBitCount` bits and shifted by `_immBitShift`.
276
+ //!
277
+ //! This offset type is sufficient for many targets that store offset as a continuous set bits within an
278
+ //! instruction word / sequence of bytes.
279
+ kSignedOffset,
280
+
281
+ //! An unsigned value having `_immBitCount` bits and shifted by `_immBitShift`.
282
+ kUnsignedOffset,
283
+
284
+ // AArch64 Specific Offset Formats
285
+ // -------------------------------
286
+
287
+ //! AARCH64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
288
+ kAArch64_ADR,
289
+
290
+ //! AARCH64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
291
+ kAArch64_ADRP,
292
+
293
+ //! Maximum value of `OffsetFormatType`.
294
+ kMaxValue = kAArch64_ADRP
295
+ };
296
+
297
+ //! Provides information about formatting offsets, absolute addresses, or their parts. Offset format is used by both
298
+ //! \ref RelocEntry and \ref LabelLink. The illustration below describes the relation of region size and offset size.
299
+ //! Region size is the size of the whole unit whereas offset size is the size of the unit that will be patched.
300
+ //!
301
+ //! ```
302
+ //! +-> Code buffer | The subject of the relocation (region) |
303
+ //! | | (Word-Offset) (Word-Size) |
304
+ //! |xxxxxxxxxxxxxxx|................|*PATCHED*|................|xxxxxxxxxxxx->
305
+ //! | |
306
+ //! [Word Offset points here]----+ +--- [WordOffset + WordSize]
307
+ //! ```
308
+ //!
309
+ //! Once the offset word has been located it can be patched like this:
310
+ //!
311
+ //! ```
312
+ //! |ImmDiscardLSB (discard LSB bits).
313
+ //! |..
314
+ //! [0000000000000iiiiiiiiiiiiiiiiiDD] - Offset value (32-bit)
315
+ //! [000000000000000iiiiiiiiiiiiiiiii] - Offset value after discard LSB.
316
+ //! [00000000000iiiiiiiiiiiiiiiii0000] - Offset value shifted by ImmBitShift.
317
+ //! [xxxxxxxxxxxiiiiiiiiiiiiiiiiixxxx] - Patched word (32-bit)
318
+ //! |...............|
319
+ //! (ImmBitCount) +- ImmBitShift
320
+ //! ```
321
+ struct OffsetFormat {
322
+ //! \name Members
323
+ //! \{
324
+
325
+ //! Type of the offset.
326
+ OffsetType _type;
327
+ //! Encoding flags.
328
+ uint8_t _flags;
329
+ //! Size of the region (in bytes) containing the offset value, if the offset value is part of an instruction,
330
+ //! otherwise it would be the same as `_valueSize`.
331
+ uint8_t _regionSize;
332
+ //! Size of the offset value, in bytes (1, 2, 4, or 8).
333
+ uint8_t _valueSize;
334
+ //! Offset of the offset value, in bytes, relative to the start of the region or data. Value offset would be
335
+ //! zero if both region size and value size are equal.
336
+ uint8_t _valueOffset;
337
+ //! Size of the offset immediate value in bits.
338
+ uint8_t _immBitCount;
339
+ //! Shift of the offset immediate value in bits in the target word.
340
+ uint8_t _immBitShift;
341
+ //! Number of least significant bits to discard before writing the immediate to the destination. All discarded
342
+ //! bits must be zero otherwise the value is invalid.
343
+ uint8_t _immDiscardLsb;
344
+
345
+ //! \}
346
+
347
+ //! \name Accessors
348
+ //! \{
349
+
350
+ //! Returns the type of the offset.
351
+ inline OffsetType type() const noexcept { return _type; }
352
+
353
+ //! Returns flags.
354
+ inline uint32_t flags() const noexcept { return _flags; }
355
+
356
+ //! Returns the size of the region/instruction where the offset is encoded.
357
+ inline uint32_t regionSize() const noexcept { return _regionSize; }
358
+
359
+ //! Returns the offset of the word relative to the start of the region where the offset is.
360
+ inline uint32_t valueOffset() const noexcept { return _valueOffset; }
361
+
362
+ //! Returns the size of the data-type (word) that contains the offset, in bytes.
363
+ inline uint32_t valueSize() const noexcept { return _valueSize; }
364
+ //! Returns the count of bits of the offset value in the data it's stored in.
365
+ inline uint32_t immBitCount() const noexcept { return _immBitCount; }
366
+ //! Returns the bit-shift of the offset value in the data it's stored in.
367
+ inline uint32_t immBitShift() const noexcept { return _immBitShift; }
368
+ //! Returns the number of least significant bits of the offset value, that must be zero and that are not part of
369
+ //! the encoded data.
370
+ inline uint32_t immDiscardLsb() const noexcept { return _immDiscardLsb; }
371
+
372
+ //! Resets this offset format to a simple data value of `dataSize` bytes.
373
+ //!
374
+ //! The region will be the same size as data and immediate bits would correspond to `dataSize * 8`. There will be
375
+ //! no immediate bit shift or discarded bits.
376
+ inline void resetToSimpleValue(OffsetType type, size_t valueSize) noexcept {
377
+ ASMJIT_ASSERT(valueSize <= 8u);
378
+
379
+ _type = type;
380
+ _flags = uint8_t(0);
381
+ _regionSize = uint8_t(valueSize);
382
+ _valueSize = uint8_t(valueSize);
383
+ _valueOffset = uint8_t(0);
384
+ _immBitCount = uint8_t(valueSize * 8u);
385
+ _immBitShift = uint8_t(0);
386
+ _immDiscardLsb = uint8_t(0);
387
+ }
388
+
389
+ inline void resetToImmValue(OffsetType type, size_t valueSize, uint32_t immBitShift, uint32_t immBitCount, uint32_t immDiscardLsb) noexcept {
390
+ ASMJIT_ASSERT(valueSize <= 8u);
391
+ ASMJIT_ASSERT(immBitShift < valueSize * 8u);
392
+ ASMJIT_ASSERT(immBitCount <= 64u);
393
+ ASMJIT_ASSERT(immDiscardLsb <= 64u);
394
+
395
+ _type = type;
396
+ _flags = uint8_t(0);
397
+ _regionSize = uint8_t(valueSize);
398
+ _valueSize = uint8_t(valueSize);
399
+ _valueOffset = uint8_t(0);
400
+ _immBitCount = uint8_t(immBitCount);
401
+ _immBitShift = uint8_t(immBitShift);
402
+ _immDiscardLsb = uint8_t(immDiscardLsb);
403
+ }
404
+
405
+ inline void setRegion(size_t regionSize, size_t valueOffset) noexcept {
406
+ _regionSize = uint8_t(regionSize);
407
+ _valueOffset = uint8_t(valueOffset);
408
+ }
409
+
410
+ inline void setLeadingAndTrailingSize(size_t leadingSize, size_t trailingSize) noexcept {
411
+ _regionSize = uint8_t(leadingSize + trailingSize + _valueSize);
412
+ _valueOffset = uint8_t(leadingSize);
413
+ }
414
+
415
+ //! \}
416
+ };
417
+
418
+ //! Relocation type.
419
+ enum class RelocType : uint32_t {
420
+ //! None/deleted (no relocation).
421
+ kNone = 0,
422
+ //! Expression evaluation, `_payload` is pointer to `Expression`.
423
+ kExpression = 1,
424
+ //! Relocate absolute to absolute.
425
+ kAbsToAbs = 2,
426
+ //! Relocate relative to absolute.
427
+ kRelToAbs = 3,
428
+ //! Relocate absolute to relative.
429
+ kAbsToRel = 4,
430
+ //! Relocate absolute to relative or use trampoline.
431
+ kX64AddressEntry = 5
432
+ };
433
+
434
+ //! Relocation entry.
435
+ struct RelocEntry {
436
+ //! \name Members
437
+ //! \{
438
+
439
+ //! Relocation id.
440
+ uint32_t _id;
441
+ //! Type of the relocation.
442
+ RelocType _relocType;
443
+ //! Format of the relocated value.
444
+ OffsetFormat _format;
445
+ //! Source section id.
446
+ uint32_t _sourceSectionId;
447
+ //! Target section id.
448
+ uint32_t _targetSectionId;
449
+ //! Source offset (relative to start of the section).
450
+ uint64_t _sourceOffset;
451
+ //! Payload (target offset, target address, expression, etc).
452
+ uint64_t _payload;
453
+
454
+ //! \}
455
+
456
+ //! \name Accessors
457
+ //! \{
458
+
459
+ inline uint32_t id() const noexcept { return _id; }
460
+
461
+ inline RelocType relocType() const noexcept { return _relocType; }
462
+ inline const OffsetFormat& format() const noexcept { return _format; }
463
+
464
+ inline uint32_t sourceSectionId() const noexcept { return _sourceSectionId; }
465
+ inline uint32_t targetSectionId() const noexcept { return _targetSectionId; }
466
+
467
+ inline uint64_t sourceOffset() const noexcept { return _sourceOffset; }
468
+ inline uint64_t payload() const noexcept { return _payload; }
469
+
470
+ Expression* payloadAsExpression() const noexcept {
471
+ return reinterpret_cast<Expression*>(uintptr_t(_payload));
472
+ }
473
+
474
+ //! \}
475
+ };
476
+
477
+ //! Type of the \ref Label.
478
+ enum class LabelType : uint8_t {
479
+ //! Anonymous label that can optionally have a name, which is only used for debugging purposes.
480
+ kAnonymous = 0,
481
+ //! Local label (always has parentId).
482
+ kLocal = 1,
483
+ //! Global label (never has parentId).
484
+ kGlobal = 2,
485
+ //! External label (references an external symbol).
486
+ kExternal = 3,
487
+
488
+ //! Maximum value of `LabelType`.
489
+ kMaxValue = kExternal
490
+ };
491
+
492
+ //! Data structure used to link either unbound labels or cross-section links.
493
+ struct LabelLink {
494
+ //! Next link (single-linked list).
495
+ LabelLink* next;
496
+ //! Section id where the label is bound.
497
+ uint32_t sectionId;
498
+ //! Relocation id or Globals::kInvalidId.
499
+ uint32_t relocId;
500
+ //! Label offset relative to the start of the section.
501
+ size_t offset;
502
+ //! Inlined rel8/rel32.
503
+ intptr_t rel;
504
+ //! Offset format information.
505
+ OffsetFormat format;
506
+ };
507
+
508
+ //! Label entry.
509
+ //!
510
+ //! Contains the following properties:
511
+ //! - Label id - This is the only thing that is set to the `Label` operand.
512
+ //! - Label name - Optional, used mostly to create executables and libraries.
513
+ //! - Label type - Type of the label, default `LabelType::kAnonymous`.
514
+ //! - Label parent id - Derived from many assemblers that allow to define a local label that falls under a global
515
+ //! label. This allows to define many labels of the same name that have different parent (global) label.
516
+ //! - Offset - offset of the label bound by `Assembler`.
517
+ //! - Links - single-linked list that contains locations of code that has to be patched when the label gets bound.
518
+ //! Every use of unbound label adds one link to `_links` list.
519
+ //! - HVal - Hash value of label's name and optionally parentId.
520
+ //! - HashNext - Hash-table implementation detail.
521
+ class LabelEntry : public ZoneHashNode {
522
+ public:
523
+ //! \name Constants
524
+ //! \{
525
+
526
+ enum : uint32_t {
527
+ //! SSO size of \ref _name.
528
+ //!
529
+ //! \cond INTERNAL
530
+ //! Let's round the size of `LabelEntry` to 64 bytes (as `ZoneAllocator` has granularity of 32 bytes anyway). This
531
+ //! gives `_name` the remaining space, which is should be 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
532
+ //! \endcond
533
+ kStaticNameSize = 64 - (sizeof(ZoneHashNode) + 8 + sizeof(Section*) + sizeof(size_t) + sizeof(LabelLink*))
534
+ };
535
+
536
+ //! \}
537
+
538
+ //! \name Members
539
+ //! \{
540
+
541
+ //! Type of the label.
542
+ LabelType _type;
543
+ //! Must be zero.
544
+ uint8_t _reserved[3];
545
+ //! Label parent id or zero.
546
+ uint32_t _parentId;
547
+ //! Label offset relative to the start of the `_section`.
548
+ uint64_t _offset;
549
+ //! Section where the label was bound.
550
+ Section* _section;
551
+ //! Label links.
552
+ LabelLink* _links;
553
+ //! Label name.
554
+ ZoneString<kStaticNameSize> _name;
555
+
556
+ //! \}
557
+
558
+ //! \name Accessors
559
+ //! \{
560
+
561
+ // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode to fill a padding that a C++
562
+ // compiler targeting 64-bit CPU will add to align the structure to 64-bits.
563
+
564
+ //! Returns label id.
565
+ inline uint32_t id() const noexcept { return _customData; }
566
+ //! Sets label id (internal, used only by `CodeHolder`).
567
+ inline void _setId(uint32_t id) noexcept { _customData = id; }
568
+
569
+ //! Returns label type.
570
+ inline LabelType type() const noexcept { return _type; }
571
+
572
+ //! Tests whether the label has a parent label.
573
+ inline bool hasParent() const noexcept { return _parentId != Globals::kInvalidId; }
574
+ //! Returns label's parent id.
575
+ inline uint32_t parentId() const noexcept { return _parentId; }
576
+
577
+ //! Returns the section where the label was bound.
578
+ //!
579
+ //! If the label was not yet bound the return value is `nullptr`.
580
+ inline Section* section() const noexcept { return _section; }
581
+
582
+ //! Tests whether the label has name.
583
+ inline bool hasName() const noexcept { return !_name.empty(); }
584
+
585
+ //! Returns the label's name.
586
+ //!
587
+ //! \note Local labels will return their local name without their parent part, for example ".L1".
588
+ inline const char* name() const noexcept { return _name.data(); }
589
+
590
+ //! Returns size of label's name.
591
+ //!
592
+ //! \note Label name is always null terminated, so you can use `strlen()` to get it, however, it's also cached in
593
+ //! `LabelEntry` itself, so if you want to know the size the fastest way is to call `LabelEntry::nameSize()`.
594
+ inline uint32_t nameSize() const noexcept { return _name.size(); }
595
+
596
+ //! Returns links associated with this label.
597
+ inline LabelLink* links() const noexcept { return _links; }
598
+
599
+ //! Tests whether the label is bound.
600
+ inline bool isBound() const noexcept { return _section != nullptr; }
601
+ //! Tests whether the label is bound to a the given `sectionId`.
602
+ inline bool isBoundTo(Section* section) const noexcept { return _section == section; }
603
+
604
+ //! Returns the label offset (only useful if the label is bound).
605
+ inline uint64_t offset() const noexcept { return _offset; }
606
+
607
+ //! Returns the hash-value of label's name and its parent label (if any).
608
+ //!
609
+ //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function is implemented in `Support::hashString()`
610
+ //! and `Support::hashRound()`.
611
+ inline uint32_t hashCode() const noexcept { return _hashCode; }
612
+
613
+ //! \}
614
+ };
615
+
616
+ //! Holds assembled code and data (including sections, labels, and relocation information).
617
+ //!
618
+ //! CodeHolder connects emitters with their targets. It provides them interface that can be used to query information
619
+ //! about the target environment (architecture, etc...) and API to create labels, sections, relocations, and to write
620
+ //! data to a \ref CodeBuffer, which is always part of \ref Section. More than one emitter can be attached to a single
621
+ //! CodeHolder instance at a time, which is used in practice
622
+ //!
623
+ //! CodeHolder provides interface for all emitter types. Assemblers use CodeHolder to write into \ref CodeBuffer, and
624
+ //! higher level emitters like Builder and Compiler use CodeHolder to manage labels and sections so higher level code
625
+ //! can be serialized to Assembler by \ref BaseEmitter::finalize() and \ref BaseBuilder::serializeTo().
626
+ //!
627
+ //! In order to use CodeHolder, it must be first initialized by \ref init(). After the CodeHolder has been successfully
628
+ //! initialized it can be used to hold assembled code, sections, labels, relocations, and to attach / detach code
629
+ //! emitters. After the end of code generation it can be used to query physical locations of labels and to relocate
630
+ //! the assembled code into the right address.
631
+ //!
632
+ //! \note \ref CodeHolder has an ability to attach an \ref ErrorHandler, however, the error handler is not triggered
633
+ //! by \ref CodeHolder itself, it's instead propagated to all emitters that attach to it.
634
+ class CodeHolder {
635
+ public:
636
+ ASMJIT_NONCOPYABLE(CodeHolder)
637
+
638
+ //! \name Members
639
+ //! \{
640
+
641
+ //! Environment information.
642
+ Environment _environment;
643
+ //! Base address or \ref Globals::kNoBaseAddress.
644
+ uint64_t _baseAddress;
645
+
646
+ //! Attached `Logger`, used by all consumers.
647
+ Logger* _logger;
648
+ //! Attached `ErrorHandler`.
649
+ ErrorHandler* _errorHandler;
650
+
651
+ //! Code zone (used to allocate core structures).
652
+ Zone _zone;
653
+ //! Zone allocator, used to manage internal containers.
654
+ ZoneAllocator _allocator;
655
+
656
+ //! Attached emitters.
657
+ ZoneVector<BaseEmitter*> _emitters;
658
+ //! Section entries.
659
+ ZoneVector<Section*> _sections;
660
+ //! Section entries sorted by section order and then section id.
661
+ ZoneVector<Section*> _sectionsByOrder;
662
+ //! Label entries.
663
+ ZoneVector<LabelEntry*> _labelEntries;
664
+ //! Relocation entries.
665
+ ZoneVector<RelocEntry*> _relocations;
666
+ //! Label name -> LabelEntry (only named labels).
667
+ ZoneHash<LabelEntry> _namedLabels;
668
+
669
+ //! Count of label links, which are not resolved.
670
+ size_t _unresolvedLinkCount;
671
+ //! Pointer to an address table section (or null if this section doesn't exist).
672
+ Section* _addressTableSection;
673
+ //! Address table entries.
674
+ ZoneTree<AddressTableEntry> _addressTableEntries;
675
+
676
+ //! \}
677
+
678
+ //! \name Construction & Destruction
679
+ //! \{
680
+
681
+ //! Creates an uninitialized CodeHolder (you must init() it before it can be used).
682
+ //!
683
+ //! An optional `temporary` argument can be used to initialize the first block of \ref Zone that the CodeHolder
684
+ //! uses into a temporary memory provided by the user.
685
+ ASMJIT_API explicit CodeHolder(const Support::Temporary* temporary = nullptr) noexcept;
686
+
687
+ //! \overload
688
+ inline explicit CodeHolder(const Support::Temporary& temporary) noexcept
689
+ : CodeHolder(&temporary) {}
690
+
691
+ //! Destroys the CodeHolder and frees all resources it has allocated.
692
+ ASMJIT_API ~CodeHolder() noexcept;
693
+
694
+ //! Tests whether the `CodeHolder` has been initialized.
695
+ //!
696
+ //! Emitters can be only attached to initialized `CodeHolder` instances.
697
+ inline bool isInitialized() const noexcept { return _environment.isInitialized(); }
698
+
699
+ //! Initializes CodeHolder to hold code described by the given `environment` and `baseAddress`.
700
+ ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept;
701
+ //! Detaches all code-generators attached and resets the `CodeHolder`.
702
+ ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept;
703
+
704
+ //! \}
705
+
706
+ //! \name Attach & Detach
707
+ //! \{
708
+
709
+ //! Attaches an emitter to this `CodeHolder`.
710
+ ASMJIT_API Error attach(BaseEmitter* emitter) noexcept;
711
+ //! Detaches an emitter from this `CodeHolder`.
712
+ ASMJIT_API Error detach(BaseEmitter* emitter) noexcept;
713
+
714
+ //! \}
715
+
716
+ //! \name Allocators
717
+ //! \{
718
+
719
+ //! Returns the allocator that the `CodeHolder` uses.
720
+ //!
721
+ //! \note This should be only used for AsmJit's purposes. Code holder uses arena allocator to allocate everything,
722
+ //! so anything allocated through this allocator will be invalidated by \ref CodeHolder::reset() or by CodeHolder's
723
+ //! destructor.
724
+ inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); }
725
+
726
+ //! \}
727
+
728
+ //! \name Code & Architecture
729
+ //! \{
730
+
731
+ //! Returns the target environment information.
732
+ inline const Environment& environment() const noexcept { return _environment; }
733
+
734
+ //! Returns the target architecture.
735
+ inline Arch arch() const noexcept { return environment().arch(); }
736
+ //! Returns the target sub-architecture.
737
+ inline SubArch subArch() const noexcept { return environment().subArch(); }
738
+
739
+ //! Tests whether a static base-address is set.
740
+ inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
741
+ //! Returns a static base-address or \ref Globals::kNoBaseAddress, if not set.
742
+ inline uint64_t baseAddress() const noexcept { return _baseAddress; }
743
+
744
+ //! \}
745
+
746
+ //! \name Emitters
747
+ //! \{
748
+
749
+ //! Returns a vector of attached emitters.
750
+ inline const ZoneVector<BaseEmitter*>& emitters() const noexcept { return _emitters; }
751
+
752
+ //! \}
753
+
754
+ //! \name Logging
755
+ //! \{
756
+
757
+ //! Returns the attached logger.
758
+ inline Logger* logger() const noexcept { return _logger; }
759
+ //! Attaches a `logger` to CodeHolder and propagates it to all attached emitters.
760
+ ASMJIT_API void setLogger(Logger* logger) noexcept;
761
+ //! Resets the logger to none.
762
+ inline void resetLogger() noexcept { setLogger(nullptr); }
763
+
764
+ //! \name Error Handling
765
+ //! \{
766
+
767
+ //! Tests whether the CodeHolder has an attached error handler, see \ref ErrorHandler.
768
+ inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
769
+ //! Returns the attached error handler.
770
+ inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
771
+ //! Attach an error handler to this `CodeHolder`.
772
+ ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept;
773
+ //! Resets the error handler to none.
774
+ inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
775
+
776
+ //! \}
777
+
778
+ //! \name Code Buffer
779
+ //! \{
780
+
781
+ //! Makes sure that at least `n` bytes can be added to CodeHolder's buffer `cb`.
782
+ //!
783
+ //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the behavior of the function is undefined.
784
+ ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept;
785
+
786
+ //! Reserves the size of `cb` to at least `n` bytes.
787
+ //!
788
+ //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the behavior of the function is undefined.
789
+ ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept;
790
+
791
+ //! \}
792
+
793
+ //! \name Sections
794
+ //! \{
795
+
796
+ //! Returns an array of `Section*` records.
797
+ inline const ZoneVector<Section*>& sections() const noexcept { return _sections; }
798
+ //! Returns an array of `Section*` records sorted according to section order first, then section id.
799
+ inline const ZoneVector<Section*>& sectionsByOrder() const noexcept { return _sectionsByOrder; }
800
+ //! Returns the number of sections.
801
+ inline uint32_t sectionCount() const noexcept { return _sections.size(); }
802
+
803
+ //! Tests whether the given `sectionId` is valid.
804
+ inline bool isSectionValid(uint32_t sectionId) const noexcept { return sectionId < _sections.size(); }
805
+
806
+ //! Creates a new section and return its pointer in `sectionOut`.
807
+ //!
808
+ //! Returns `Error`, does not report a possible error to `ErrorHandler`.
809
+ ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, SectionFlags flags = SectionFlags::kNone, uint32_t alignment = 1, int32_t order = 0) noexcept;
810
+
811
+ //! Returns a section entry of the given index.
812
+ inline Section* sectionById(uint32_t sectionId) const noexcept { return _sections[sectionId]; }
813
+
814
+ //! Returns section-id that matches the given `name`.
815
+ //!
816
+ //! If there is no such section `Section::kInvalidId` is returned.
817
+ ASMJIT_API Section* sectionByName(const char* name, size_t nameSize = SIZE_MAX) const noexcept;
818
+
819
+ //! Returns '.text' section (section that commonly represents code).
820
+ //!
821
+ //! \note Text section is always the first section in \ref CodeHolder::sections() array.
822
+ inline Section* textSection() const noexcept { return _sections[0]; }
823
+
824
+ //! Tests whether '.addrtab' section exists.
825
+ inline bool hasAddressTable() const noexcept { return _addressTableSection != nullptr; }
826
+
827
+ //! Returns '.addrtab' section.
828
+ //!
829
+ //! This section is used exclusively by AsmJit to store absolute 64-bit
830
+ //! addresses that cannot be encoded in instructions like 'jmp' or 'call'.
831
+ //!
832
+ //! \note This section is created on demand, the returned pointer can be null.
833
+ inline Section* addressTableSection() const noexcept { return _addressTableSection; }
834
+
835
+ //! Ensures that '.addrtab' section exists (creates it if it doesn't) and
836
+ //! returns it. Can return `nullptr` on out of memory condition.
837
+ ASMJIT_API Section* ensureAddressTableSection() noexcept;
838
+
839
+ //! Used to add an address to an address table.
840
+ //!
841
+ //! This implicitly calls `ensureAddressTableSection()` and then creates `AddressTableEntry` that is inserted
842
+ //! to `_addressTableEntries`. If the address already exists this operation does nothing as the same addresses
843
+ //! use the same slot.
844
+ //!
845
+ //! This function should be considered internal as it's used by assemblers to insert an absolute address into the
846
+ //! address table. Inserting address into address table without creating a particula relocation entry makes no sense.
847
+ ASMJIT_API Error addAddressToAddressTable(uint64_t address) noexcept;
848
+
849
+ //! \}
850
+
851
+ //! \name Labels & Symbols
852
+ //! \{
853
+
854
+ //! Returns array of `LabelEntry*` records.
855
+ inline const ZoneVector<LabelEntry*>& labelEntries() const noexcept { return _labelEntries; }
856
+
857
+ //! Returns number of labels created.
858
+ inline uint32_t labelCount() const noexcept { return _labelEntries.size(); }
859
+
860
+ //! Tests whether the label having `id` is valid (i.e. created by `newLabelEntry()`).
861
+ inline bool isLabelValid(uint32_t labelId) const noexcept {
862
+ return labelId < _labelEntries.size();
863
+ }
864
+
865
+ //! Tests whether the `label` is valid (i.e. created by `newLabelEntry()`).
866
+ inline bool isLabelValid(const Label& label) const noexcept {
867
+ return label.id() < _labelEntries.size();
868
+ }
869
+
870
+ //! \overload
871
+ inline bool isLabelBound(uint32_t labelId) const noexcept {
872
+ return isLabelValid(labelId) && _labelEntries[labelId]->isBound();
873
+ }
874
+
875
+ //! Tests whether the `label` is already bound.
876
+ //!
877
+ //! Returns `false` if the `label` is not valid.
878
+ inline bool isLabelBound(const Label& label) const noexcept {
879
+ return isLabelBound(label.id());
880
+ }
881
+
882
+ //! Returns LabelEntry of the given label `id`.
883
+ inline LabelEntry* labelEntry(uint32_t labelId) const noexcept {
884
+ return isLabelValid(labelId) ? _labelEntries[labelId] : static_cast<LabelEntry*>(nullptr);
885
+ }
886
+
887
+ //! Returns LabelEntry of the given `label`.
888
+ inline LabelEntry* labelEntry(const Label& label) const noexcept {
889
+ return labelEntry(label.id());
890
+ }
891
+
892
+ //! Returns offset of a `Label` by its `labelId`.
893
+ //!
894
+ //! The offset returned is relative to the start of the section. Zero offset is returned for unbound labels,
895
+ //! which is their initial offset value.
896
+ inline uint64_t labelOffset(uint32_t labelId) const noexcept {
897
+ ASMJIT_ASSERT(isLabelValid(labelId));
898
+ return _labelEntries[labelId]->offset();
899
+ }
900
+
901
+ //! \overload
902
+ inline uint64_t labelOffset(const Label& label) const noexcept {
903
+ return labelOffset(label.id());
904
+ }
905
+
906
+ //! Returns offset of a label by it's `labelId` relative to the base offset.
907
+ //!
908
+ //! \remarks The offset of the section where the label is bound must be valid in order to use this function,
909
+ //! otherwise the value returned will not be reliable.
910
+ inline uint64_t labelOffsetFromBase(uint32_t labelId) const noexcept {
911
+ ASMJIT_ASSERT(isLabelValid(labelId));
912
+ const LabelEntry* le = _labelEntries[labelId];
913
+ return (le->isBound() ? le->section()->offset() : uint64_t(0)) + le->offset();
914
+ }
915
+
916
+ //! \overload
917
+ inline uint64_t labelOffsetFromBase(const Label& label) const noexcept {
918
+ return labelOffsetFromBase(label.id());
919
+ }
920
+
921
+ //! Creates a new anonymous label and return its id in `idOut`.
922
+ //!
923
+ //! Returns `Error`, does not report error to `ErrorHandler`.
924
+ ASMJIT_API Error newLabelEntry(LabelEntry** entryOut) noexcept;
925
+
926
+ //! Creates a new named \ref LabelEntry of the given label `type`.
927
+ //!
928
+ //! \param entryOut Where to store the created \ref LabelEntry.
929
+ //! \param name The name of the label.
930
+ //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is a null terminated string, which
931
+ //! means that the `CodeHolder` will use `strlen()` to determine the length.
932
+ //! \param type The type of the label to create, see \ref LabelType.
933
+ //! \param parentId Parent id of a local label, otherwise it must be \ref Globals::kInvalidId.
934
+ //! \retval Always returns \ref Error, does not report a possible error to the attached \ref ErrorHandler.
935
+ //!
936
+ //! AsmJit has a support for local labels (\ref LabelType::kLocal) which require a parent label id (parentId).
937
+ //! The names of local labels can conflict with names of other local labels that have a different parent. In
938
+ //! addition, AsmJit supports named anonymous labels, which are useful only for debugging purposes as the
939
+ //! anonymous name will have a name, which will be formatted, but the label itself cannot be queried by such
940
+ //! name.
941
+ ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, LabelType type, uint32_t parentId = Globals::kInvalidId) noexcept;
942
+
943
+ //! Returns a label by name.
944
+ //!
945
+ //! If the named label doesn't a default constructed \ref Label is returned,
946
+ //! which has its id set to \ref Globals::kInvalidId.
947
+ inline Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept {
948
+ return Label(labelIdByName(name, nameSize, parentId));
949
+ }
950
+
951
+ //! Returns a label id by name.
952
+ //!
953
+ //! If the named label doesn't exist \ref Globals::kInvalidId is returned.
954
+ ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept;
955
+
956
+ //! Tests whether there are any unresolved label links.
957
+ inline bool hasUnresolvedLinks() const noexcept { return _unresolvedLinkCount != 0; }
958
+ //! Returns the number of label links, which are unresolved.
959
+ inline size_t unresolvedLinkCount() const noexcept { return _unresolvedLinkCount; }
960
+
961
+ //! Creates a new label-link used to store information about yet unbound labels.
962
+ //!
963
+ //! Returns `null` if the allocation failed.
964
+ ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel, const OffsetFormat& format) noexcept;
965
+
966
+ //! Resolves cross-section links (`LabelLink`) associated with each label that was used as a destination in code
967
+ //! of a different section. It's only useful to people that use multiple sections as it will do nothing if the code
968
+ //! only contains a single section in which cross-section links are not possible.
969
+ ASMJIT_API Error resolveUnresolvedLinks() noexcept;
970
+
971
+ //! Binds a label to a given `sectionId` and `offset` (relative to start of the section).
972
+ //!
973
+ //! This function is generally used by `BaseAssembler::bind()` to do the heavy lifting.
974
+ ASMJIT_API Error bindLabel(const Label& label, uint32_t sectionId, uint64_t offset) noexcept;
975
+
976
+ //! \}
977
+
978
+ //! \name Relocations
979
+ //! \{
980
+
981
+ //! Tests whether the code contains relocation entries.
982
+ inline bool hasRelocEntries() const noexcept { return !_relocations.empty(); }
983
+ //! Returns array of `RelocEntry*` records.
984
+ inline const ZoneVector<RelocEntry*>& relocEntries() const noexcept { return _relocations; }
985
+
986
+ //! Returns a RelocEntry of the given `id`.
987
+ inline RelocEntry* relocEntry(uint32_t id) const noexcept { return _relocations[id]; }
988
+
989
+ //! Creates a new relocation entry of type `relocType`.
990
+ //!
991
+ //! Additional fields can be set after the relocation entry was created.
992
+ ASMJIT_API Error newRelocEntry(RelocEntry** dst, RelocType relocType) noexcept;
993
+
994
+ //! \}
995
+
996
+ //! \name Utilities
997
+ //! \{
998
+
999
+ //! Flattens all sections by recalculating their offsets, starting at 0.
1000
+ //!
1001
+ //! \note This should never be called more than once.
1002
+ ASMJIT_API Error flatten() noexcept;
1003
+
1004
+ //! Returns computed the size of code & data of all sections.
1005
+ //!
1006
+ //! \note All sections will be iterated over and the code size returned would represent the minimum code size of
1007
+ //! all combined sections after applying minimum alignment. Code size may decrease after calling `flatten()` and
1008
+ //! `relocateToBase()`.
1009
+ ASMJIT_API size_t codeSize() const noexcept;
1010
+
1011
+ //! Relocates the code to the given `baseAddress`.
1012
+ //!
1013
+ //! \param baseAddress Absolute base address where the code will be relocated to. Please note that nothing is
1014
+ //! copied to such base address, it's just an absolute value used by the relocator to resolve all stored relocations.
1015
+ //!
1016
+ //! \note This should never be called more than once.
1017
+ ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept;
1018
+
1019
+ //! Copies a single section into `dst`.
1020
+ ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, CopySectionFlags copyFlags = CopySectionFlags::kNone) noexcept;
1021
+
1022
+ //! Copies all sections into `dst`.
1023
+ //!
1024
+ //! This should only be used if the data was flattened and there are no gaps between the sections. The `dstSize`
1025
+ //! is always checked and the copy will never write anything outside the provided buffer.
1026
+ ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, CopySectionFlags copyFlags = CopySectionFlags::kNone) noexcept;
1027
+
1028
+ //! \}
1029
+ };
1030
+
1031
+ //! \}
1032
+
1033
+ ASMJIT_END_NAMESPACE
1034
+
1035
+ #endif // ASMJIT_CORE_CODEHOLDER_H_INCLUDED