asmjit 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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