evoasm 0.0.2.pre7 → 0.1.0.pre2

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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/.gdbinit +41 -0
  3. data/.gitignore +1 -2
  4. data/.gitmodules +3 -0
  5. data/.rubocop.yml +8 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.md +660 -0
  8. data/Makefile +1 -1
  9. data/README.md +17 -9
  10. data/Rakefile +39 -107
  11. data/bin/gdb +1 -1
  12. data/bin/gdb_loop +4 -0
  13. data/docs/FindingInstructions.md +17 -0
  14. data/docs/JIT.md +14 -0
  15. data/docs/SymbolicRegression.md +102 -0
  16. data/docs/Visualization.md +29 -0
  17. data/docs/examples/bit_insts.rb +44 -0
  18. data/docs/examples/jit.rb +26 -0
  19. data/docs/examples/loss.gif +0 -0
  20. data/docs/examples/program.png +0 -0
  21. data/docs/examples/sym_reg.rb +64 -0
  22. data/docs/examples/vis.rb +38 -0
  23. data/evoasm.gemspec +21 -15
  24. data/ext/evoasm_ext/Rakefile +3 -0
  25. data/ext/evoasm_ext/compile.rake +35 -0
  26. data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.c +226 -0
  27. data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.h +84 -0
  28. data/ext/evoasm_ext/libevoasm/src/evoasm-arch.c +52 -0
  29. data/ext/evoasm_ext/libevoasm/src/evoasm-arch.h +101 -0
  30. data/ext/evoasm_ext/libevoasm/src/evoasm-bitmap.h +158 -0
  31. data/ext/evoasm_ext/libevoasm/src/evoasm-buf.c +204 -0
  32. data/ext/evoasm_ext/libevoasm/src/evoasm-buf.h +109 -0
  33. data/ext/evoasm_ext/libevoasm/src/evoasm-domain.c +124 -0
  34. data/ext/evoasm_ext/libevoasm/src/evoasm-domain.h +279 -0
  35. data/ext/evoasm_ext/libevoasm/src/evoasm-error.c +65 -0
  36. data/ext/evoasm_ext/libevoasm/src/evoasm-error.h +108 -0
  37. data/ext/evoasm_ext/{evoasm-log.c → libevoasm/src/evoasm-log.c} +36 -18
  38. data/ext/evoasm_ext/libevoasm/src/evoasm-log.h +93 -0
  39. data/ext/evoasm_ext/libevoasm/src/evoasm-param.c +22 -0
  40. data/ext/evoasm_ext/libevoasm/src/evoasm-param.h +33 -0
  41. data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.c +192 -0
  42. data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.h +60 -0
  43. data/ext/evoasm_ext/libevoasm/src/evoasm-pop.c +1323 -0
  44. data/ext/evoasm_ext/libevoasm/src/evoasm-pop.h +107 -0
  45. data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.c +116 -0
  46. data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.h +60 -0
  47. data/ext/evoasm_ext/libevoasm/src/evoasm-program.c +1827 -0
  48. data/ext/evoasm_ext/libevoasm/src/evoasm-program.h +167 -0
  49. data/ext/evoasm_ext/libevoasm/src/evoasm-rand.c +65 -0
  50. data/ext/evoasm_ext/libevoasm/src/evoasm-rand.h +76 -0
  51. data/ext/evoasm_ext/libevoasm/src/evoasm-signal.c +106 -0
  52. data/ext/evoasm_ext/libevoasm/src/evoasm-signal.h +58 -0
  53. data/ext/evoasm_ext/libevoasm/src/evoasm-util.h +112 -0
  54. data/ext/evoasm_ext/libevoasm/src/evoasm-x64.c +925 -0
  55. data/ext/evoasm_ext/libevoasm/src/evoasm-x64.h +277 -0
  56. data/ext/evoasm_ext/libevoasm/src/evoasm.c +28 -0
  57. data/ext/evoasm_ext/libevoasm/src/evoasm.h +35 -0
  58. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-enums.h +2077 -0
  59. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.c +191203 -0
  60. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.h +1713 -0
  61. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.c +348 -0
  62. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.h +93 -0
  63. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.c +51 -0
  64. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.h +509 -0
  65. data/lib/evoasm.rb +28 -11
  66. data/lib/evoasm/buffer.rb +105 -0
  67. data/lib/evoasm/capstone.rb +100 -0
  68. data/lib/evoasm/domain.rb +116 -0
  69. data/lib/evoasm/error.rb +37 -16
  70. data/lib/evoasm/exception_error.rb +19 -0
  71. data/lib/evoasm/ffi_ext.rb +53 -0
  72. data/lib/evoasm/libevoasm.rb +286 -0
  73. data/lib/evoasm/libevoasm/x64_enums.rb +1967 -0
  74. data/lib/evoasm/parameter.rb +20 -0
  75. data/lib/evoasm/population.rb +145 -0
  76. data/lib/evoasm/population/parameters.rb +227 -0
  77. data/lib/evoasm/population/plotter.rb +89 -0
  78. data/lib/evoasm/prng.rb +64 -0
  79. data/lib/evoasm/program.rb +195 -12
  80. data/lib/evoasm/program/io.rb +144 -0
  81. data/lib/evoasm/test.rb +8 -0
  82. data/lib/evoasm/version.rb +1 -1
  83. data/lib/evoasm/x64.rb +115 -0
  84. data/lib/evoasm/x64/cpu_state.rb +95 -0
  85. data/lib/evoasm/x64/instruction.rb +109 -0
  86. data/lib/evoasm/x64/operand.rb +156 -0
  87. data/lib/evoasm/x64/parameters.rb +211 -0
  88. data/test/helpers/population_helper.rb +128 -0
  89. data/test/helpers/test_helper.rb +1 -0
  90. data/test/helpers/x64_helper.rb +24 -0
  91. data/test/integration/bitwise_reverse_test.rb +41 -0
  92. data/test/integration/gcd_test.rb +52 -0
  93. data/test/integration/popcnt_test.rb +46 -0
  94. data/test/integration/sym_reg_test.rb +68 -0
  95. data/test/unit/evoasm/buffer_test.rb +48 -0
  96. data/test/unit/evoasm/capstone_test.rb +18 -0
  97. data/test/unit/evoasm/domain_test.rb +55 -0
  98. data/test/unit/evoasm/population/parameters_test.rb +106 -0
  99. data/test/unit/evoasm/population_test.rb +96 -0
  100. data/test/unit/evoasm/prng_test.rb +47 -0
  101. data/test/unit/evoasm/x64/cpu_state_test.rb +73 -0
  102. data/test/unit/evoasm/x64/encoding_test.rb +320 -0
  103. data/test/unit/evoasm/x64/instruction_access_test.rb +177 -0
  104. data/test/unit/evoasm/x64/instruction_encoding_test.rb +780 -0
  105. data/test/unit/evoasm/x64/instruction_test.rb +62 -0
  106. data/test/unit/evoasm/x64/parameters_test.rb +65 -0
  107. data/test/unit/evoasm/x64_test.rb +52 -0
  108. metadata +195 -89
  109. data/Gemfile.rake +0 -8
  110. data/Gemfile.rake.lock +0 -51
  111. data/LICENSE.txt +0 -373
  112. data/data/tables/README.md +0 -19
  113. data/data/tables/x64.csv +0 -1684
  114. data/data/templates/evoasm-x64.c.erb +0 -319
  115. data/data/templates/evoasm-x64.h.erb +0 -126
  116. data/examples/abs.yml +0 -20
  117. data/examples/popcnt.yml +0 -17
  118. data/examples/sym_reg.yml +0 -26
  119. data/exe/evoasm-search +0 -13
  120. data/ext/evoasm_ext/evoasm-alloc.c +0 -145
  121. data/ext/evoasm_ext/evoasm-alloc.h +0 -59
  122. data/ext/evoasm_ext/evoasm-arch.c +0 -44
  123. data/ext/evoasm_ext/evoasm-arch.h +0 -161
  124. data/ext/evoasm_ext/evoasm-bitmap.h +0 -114
  125. data/ext/evoasm_ext/evoasm-buf.c +0 -130
  126. data/ext/evoasm_ext/evoasm-buf.h +0 -47
  127. data/ext/evoasm_ext/evoasm-error.c +0 -31
  128. data/ext/evoasm_ext/evoasm-error.h +0 -75
  129. data/ext/evoasm_ext/evoasm-free-list.c.tmpl +0 -121
  130. data/ext/evoasm_ext/evoasm-free-list.h.tmpl +0 -86
  131. data/ext/evoasm_ext/evoasm-log.h +0 -69
  132. data/ext/evoasm_ext/evoasm-misc.c +0 -23
  133. data/ext/evoasm_ext/evoasm-misc.h +0 -282
  134. data/ext/evoasm_ext/evoasm-param.h +0 -37
  135. data/ext/evoasm_ext/evoasm-search.c +0 -2145
  136. data/ext/evoasm_ext/evoasm-search.h +0 -214
  137. data/ext/evoasm_ext/evoasm-util.h +0 -40
  138. data/ext/evoasm_ext/evoasm-x64.c +0 -275624
  139. data/ext/evoasm_ext/evoasm-x64.h +0 -5436
  140. data/ext/evoasm_ext/evoasm.c +0 -7
  141. data/ext/evoasm_ext/evoasm.h +0 -23
  142. data/ext/evoasm_ext/evoasm_ext.c +0 -1757
  143. data/ext/evoasm_ext/extconf.rb +0 -31
  144. data/lib/evoasm/cli.rb +0 -6
  145. data/lib/evoasm/cli/search.rb +0 -127
  146. data/lib/evoasm/core_ext.rb +0 -1
  147. data/lib/evoasm/core_ext/array.rb +0 -9
  148. data/lib/evoasm/core_ext/integer.rb +0 -10
  149. data/lib/evoasm/core_ext/kwstruct.rb +0 -13
  150. data/lib/evoasm/core_ext/range.rb +0 -5
  151. data/lib/evoasm/examples.rb +0 -27
  152. data/lib/evoasm/gen.rb +0 -8
  153. data/lib/evoasm/gen/enum.rb +0 -169
  154. data/lib/evoasm/gen/name_util.rb +0 -80
  155. data/lib/evoasm/gen/state.rb +0 -176
  156. data/lib/evoasm/gen/state_dsl.rb +0 -152
  157. data/lib/evoasm/gen/strio.rb +0 -27
  158. data/lib/evoasm/gen/translator.rb +0 -1102
  159. data/lib/evoasm/gen/version.rb +0 -5
  160. data/lib/evoasm/gen/x64.rb +0 -237
  161. data/lib/evoasm/gen/x64/funcs.rb +0 -495
  162. data/lib/evoasm/gen/x64/inst.rb +0 -781
  163. data/lib/evoasm/search.rb +0 -40
  164. data/lib/evoasm/tasks/gen_task.rb +0 -86
  165. data/lib/evoasm/tasks/template_task.rb +0 -52
  166. data/test/test_helper.rb +0 -1
  167. data/test/x64/test_helper.rb +0 -19
  168. data/test/x64/x64_test.rb +0 -87
@@ -0,0 +1,177 @@
1
+ require 'evoasm/test'
2
+ require 'evoasm/buffer'
3
+ require 'evoasm/x64'
4
+ require 'evoasm/x64/cpu_state'
5
+
6
+ require 'x64_helper'
7
+
8
+ module Evoasm
9
+ module X64
10
+ class InstructionAccessTest < Minitest::Test
11
+ include X64Helper
12
+
13
+ def setup
14
+ super
15
+ end
16
+
17
+ def self.test_order
18
+ :alpha
19
+ end
20
+
21
+ PARAMETERS = %i(reg0 reg1 reg2 reg3 imm0)
22
+
23
+ def random_parameters(instruction)
24
+ parameters = Evoasm::X64::Parameters.new(basic: true)
25
+ instruction.parameters.each do |parameter|
26
+ if PARAMETERS.include? parameter.name
27
+ parameter_value = parameter.domain.rand
28
+ parameters[parameter.name] = parameter_value
29
+ end
30
+ end
31
+
32
+ parameters
33
+ end
34
+
35
+ def accessed_registers(registers, instruction, parameters, mode)
36
+ registers.map do |register|
37
+ word = instruction.operands.find do |operand|
38
+ case mode
39
+ when :write
40
+ next false unless operand.written? || operand.maybe_written?
41
+ when :read
42
+ next false unless operand.read?
43
+ else
44
+ raise
45
+ end
46
+
47
+ next true if operand.register == register
48
+
49
+ parameter_name = operand.parameter&.name
50
+ next false if parameter_name.nil?
51
+ parameters[parameter_name] == register
52
+ end&.word
53
+
54
+ [register, word] if word
55
+ end.compact.to_h
56
+ end
57
+
58
+ def self.define_write_test(instruction)
59
+ define_method :"test_#{instruction.name}_writes" do
60
+ buffer = Evoasm::Buffer.new 1024, :mmap
61
+
62
+ 100.times do
63
+ parameters = random_parameters(instruction)
64
+
65
+ cpu_state_before = CPUState.new
66
+ cpu_state_after = CPUState.new
67
+
68
+ buffer.reset
69
+ X64.emit_stack_frame buffer do
70
+ cpu_state_before.emit_store buffer
71
+ instruction.encode parameters, buffer, basic: true
72
+ cpu_state_after.emit_store buffer
73
+ end
74
+
75
+ begin
76
+ buffer.execute!
77
+
78
+ cpu_state_diff = cpu_state_before.xor cpu_state_after
79
+
80
+ written_registers = cpu_state_diff.to_h.select do |register, value|
81
+ # Ignore for now
82
+ # MXCSR is almost never checked
83
+ # and does not really affect code flow
84
+ register != :mxcsr && !value.all? { |v| v == 0 }
85
+ end.map(&:first)
86
+
87
+ expected_written_registers = accessed_registers(written_registers, instruction, parameters, :write).keys
88
+ unexpected_written_registers = written_registers - expected_written_registers
89
+
90
+ assert_empty unexpected_written_registers, "No operand found that writes to #{unexpected_written_registers} ("\
91
+ "(#{instruction.name} #{parameters.inspect})."\
92
+ "The following registers have been written to #{written_registers}"
93
+
94
+ #buffer.__log__ :warn
95
+ rescue ExceptionError
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ def self.define_read_test(instruction)
102
+ define_method :"test_#{instruction.name}_reads" do
103
+ buffer = Evoasm::Buffer.new 1024, :mmap
104
+
105
+ 20.times do
106
+ parameters = random_parameters(instruction)
107
+
108
+ cpu_state_before = CPUState.new
109
+ read_registers = accessed_registers(X64.registers, instruction, parameters, :read)
110
+ read_registers.each do |read_register, _|
111
+ cpu_state_before[read_register] = Array.new(4) { rand(999999999) }
112
+ end
113
+ #p [instruction.name, accessed_registers(X64.registers, instruction, parameters, :read)]
114
+
115
+ non_read_registers = X64.registers - accessed_registers(X64.registers, instruction, parameters, :read).keys
116
+ written_registers = accessed_registers(X64.registers, instruction, parameters, :write)
117
+ expected_cpu_state_after = nil
118
+
119
+ 20.times do
120
+ non_read_registers.each do |non_read_register|
121
+ value = Array.new(4) { rand(999999999) }
122
+ #next if non_read_register == :rflags
123
+ #p [non_read_register, value]
124
+ cpu_state_before[non_read_register] = value
125
+ end
126
+ #parameters = random_parameters(instruction)
127
+
128
+ #p cpu_state_before.get :rflags
129
+
130
+ buffer.reset
131
+
132
+ cpu_state_after = CPUState.new
133
+ X64.emit_stack_frame buffer do
134
+ cpu_state_before.emit_load buffer
135
+ instruction.encode parameters, buffer, basic: true
136
+ cpu_state_after.emit_store buffer
137
+ end
138
+
139
+ begin
140
+ #buffer.__log__ :warn
141
+ buffer.execute!
142
+
143
+ if expected_cpu_state_after
144
+ written_registers.each do |written_register, written_word|
145
+ next if written_register == :rflags
146
+ message = "#{written_register} mismatch (#{cpu_state_before[written_register]})"\
147
+ "#{non_read_registers}"
148
+ #p [instruction.name, parameters, cpu_state_after.to_h]
149
+ assert_equal expected_cpu_state_after[written_register, written_word], cpu_state_after[written_register, written_word], message
150
+ end
151
+ else
152
+ #p ["pre", instruction.name, parameters, cpu_state_after.to_h]
153
+ expected_cpu_state_after = cpu_state_after
154
+ end
155
+
156
+ rescue ExceptionError
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+
164
+ X64.instruction_names(:rflags, :mxcsr, :gp, :mm, :xmm, :zmm).each do |instruction_name|
165
+ instruction = Evoasm::X64.instruction instruction_name
166
+ next unless instruction.basic?
167
+ next if instruction.name == :std
168
+
169
+ define_write_test instruction
170
+
171
+ next if instruction.name =~ /^cmov/
172
+ #next if instruction.name =~ /^pins/
173
+ define_read_test instruction
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,780 @@
1
+ require 'evoasm/test'
2
+
3
+ require 'x64_helper'
4
+
5
+ module Evoasm
6
+ module X64
7
+ class InstructionEncodingTest < Minitest::Test
8
+ include X64Helper
9
+
10
+ def setup
11
+ super
12
+ end
13
+
14
+ def self.test_order
15
+ :alpha
16
+ end
17
+
18
+ def test_simd_cmp
19
+ assert_disassembles_to 'cmpeqpd xmm0, xmm1', :cmppd_xmm_xmmm128_imm8,
20
+ reg0: :xmm0, reg1: :xmm1, imm0: 0
21
+
22
+ assert_disassembles_to 'cmpeqps xmm0, xmm1', :cmpps_xmm_xmmm128_imm8,
23
+ reg0: :xmm0, reg1: :xmm1, imm0: 0
24
+
25
+ assert_disassembles_to 'cmpeqsd xmm0, xmm1', :cmpsd_xmm_xmmm64_imm8,
26
+ reg0: :xmm0, reg1: :xmm1, imm0: 0
27
+
28
+ assert_disassembles_to 'cmpeqss xmm0, xmm1', :cmpss_xmm_xmmm32_imm8,
29
+ reg0: :xmm0, reg1: :xmm1, imm0: 0
30
+
31
+
32
+ assert_disassembles_to 'vcmpeqpd xmm0, xmm1, xmm2', :vcmppd_xmm_xmm_xmmm128_imm8,
33
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0
34
+
35
+ assert_disassembles_to 'vcmpeqps xmm0, xmm1, xmm2', :vcmpps_xmm_xmm_xmmm128_imm8,
36
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0
37
+
38
+ assert_disassembles_to 'vcmpeqsd xmm0, xmm1, xmm2', :vcmpsd_xmm_xmm_xmmm64_imm8,
39
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0
40
+
41
+ assert_disassembles_to 'vcmpeqss xmm0, xmm1, xmm2', :vcmpss_xmm_xmm_xmmm32_imm8,
42
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0
43
+
44
+
45
+ assert_disassembles_to 'vcmpeqpd ymm0, ymm1, ymm2', :vcmppd_ymm_ymm_ymmm256_imm8,
46
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0
47
+
48
+ assert_disassembles_to 'vcmpeqps ymm0, ymm1, ymm2', :vcmpps_ymm_ymm_ymmm256_imm8,
49
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0
50
+
51
+
52
+ assert_disassembles_to 'cmpordpd xmm0, xmm1', :cmppd_xmm_xmmm128_imm8,
53
+ reg0: :xmm0, reg1: :xmm1, imm0: 7
54
+
55
+ assert_disassembles_to 'cmpordps xmm0, xmm1', :cmpps_xmm_xmmm128_imm8,
56
+ reg0: :xmm0, reg1: :xmm1, imm0: 7
57
+
58
+ assert_disassembles_to 'cmpordsd xmm0, xmm1', :cmpsd_xmm_xmmm64_imm8,
59
+ reg0: :xmm0, reg1: :xmm1, imm0: 7
60
+
61
+ assert_disassembles_to 'cmpordss xmm0, xmm1', :cmpss_xmm_xmmm32_imm8,
62
+ reg0: :xmm0, reg1: :xmm1, imm0: 7
63
+
64
+
65
+ assert_disassembles_to 'vcmpordpd xmm0, xmm1, xmm2', :vcmppd_xmm_xmm_xmmm128_imm8,
66
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 7
67
+
68
+ assert_disassembles_to 'vcmpordps xmm0, xmm1, xmm2', :vcmpps_xmm_xmm_xmmm128_imm8,
69
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 7
70
+
71
+ assert_disassembles_to 'vcmpordsd xmm0, xmm1, xmm2', :vcmpsd_xmm_xmm_xmmm64_imm8,
72
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 7
73
+
74
+ assert_disassembles_to 'vcmpordss xmm0, xmm1, xmm2', :vcmpss_xmm_xmm_xmmm32_imm8,
75
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 7
76
+
77
+
78
+ assert_disassembles_to 'vcmpordpd ymm0, ymm1, ymm2', :vcmppd_ymm_ymm_ymmm256_imm8,
79
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 7
80
+
81
+
82
+ assert_disassembles_to 'vcmpordps ymm0, ymm1, ymm2', :vcmpps_ymm_ymm_ymmm256_imm8,
83
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 7
84
+
85
+
86
+ assert_disassembles_to 'vcmptrue_uspd xmm0, xmm1, xmm2', :vcmppd_xmm_xmm_xmmm128_imm8,
87
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0x1f
88
+
89
+ assert_disassembles_to 'vcmptrue_usps xmm0, xmm1, xmm2', :vcmpps_xmm_xmm_xmmm128_imm8,
90
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0x1f
91
+
92
+ assert_disassembles_to 'vcmptrue_ussd xmm0, xmm1, xmm2', :vcmpsd_xmm_xmm_xmmm64_imm8,
93
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0x1f
94
+
95
+ assert_disassembles_to 'vcmptrue_uspd ymm0, ymm1, ymm2', :vcmppd_ymm_ymm_ymmm256_imm8,
96
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0x1f
97
+
98
+ assert_disassembles_to 'vcmptrue_usps ymm0, ymm1, ymm2', :vcmpps_ymm_ymm_ymmm256_imm8,
99
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, imm0: 0x1f
100
+
101
+ end
102
+
103
+ def test_cmps
104
+ assert_assembles_to "\xA6", :cmpsb
105
+ assert_assembles_to "\x66\xA7", :cmpsw
106
+ assert_assembles_to "\xA7", :cmpsd
107
+ assert_assembles_to "\x48\xA7", :cmpsq
108
+
109
+ assert_assembles_to "\xF3\xA6", :repe_cmpsb
110
+ assert_assembles_to "\xF3\x66\xA7", :repe_cmpsw
111
+ assert_assembles_to "\xF3\xA7", :repe_cmpsd
112
+ assert_assembles_to "\xF3\x48\xA7", :repe_cmpsq
113
+
114
+ assert_assembles_to "\xF2\xA6", :repne_cmpsb
115
+ assert_assembles_to "\xF2\x66\xA7", :repne_cmpsw
116
+ assert_assembles_to "\xF2\xA7", :repne_cmpsd
117
+ assert_assembles_to "\xF2\x48\xA7", :repne_cmpsq
118
+ end
119
+
120
+ def test_lods
121
+ assert_assembles_to "\xAC", :lodsb
122
+ assert_assembles_to "\x66\xAD", :lodsw
123
+ assert_assembles_to "\xAD", :lodsd
124
+ assert_assembles_to "\x48\xAD", :lodsq
125
+
126
+ assert_assembles_to "\xF3\xAC", :rep_lodsb
127
+ assert_assembles_to "\xF3\x66\xAD", :rep_lodsw
128
+ assert_assembles_to "\xF3\xAD", :rep_lodsd
129
+ assert_assembles_to "\xF3\x48\xAD", :rep_lodsq
130
+ end
131
+
132
+ def test_movs
133
+ assert_assembles_to "\xA4", :movsb
134
+ assert_assembles_to "\x66\xA5", :movsw
135
+ assert_assembles_to "\xA5", :movsd
136
+ assert_assembles_to "\x48\xA5", :movsq
137
+
138
+ assert_assembles_to "\xF3\xA4", :rep_movsb
139
+ assert_assembles_to "\xF3\x66\xA5", :rep_movsw
140
+ assert_assembles_to "\xF3\xA5", :rep_movsd
141
+ assert_assembles_to "\xF3\x48\xA5", :rep_movsq
142
+ end
143
+
144
+ def test_scas
145
+ assert_assembles_to "\xAE", :scasb
146
+ assert_assembles_to "\x66\xAF", :scasw
147
+ assert_assembles_to "\xAF", :scasd
148
+ assert_assembles_to "\x48\xAF", :scasq
149
+
150
+ assert_assembles_to "\xF3\xAE", :repe_scasb
151
+ assert_assembles_to "\xF3\x66\xAF", :repe_scasw
152
+ assert_assembles_to "\xF3\xAF", :repe_scasd
153
+ assert_assembles_to "\xF3\x48\xAF", :repe_scasq
154
+
155
+ assert_assembles_to "\xF2\xAE", :repne_scasb
156
+ assert_assembles_to "\xF2\x66\xAF", :repne_scasw
157
+ assert_assembles_to "\xF2\xAF", :repne_scasd
158
+ assert_assembles_to "\xF2\x48\xAF", :repne_scasq
159
+ end
160
+
161
+ def test_stos
162
+ assert_assembles_to "\xAA", :stosb
163
+ assert_assembles_to "\x66\xAB", :stosw
164
+ assert_assembles_to "\xAB", :stosd
165
+ assert_assembles_to "\x48\xAB", :stosq
166
+
167
+ assert_assembles_to "\xF3\xAA", :rep_stosb
168
+ assert_assembles_to "\xF3\x66\xAB", :rep_stosw
169
+ assert_assembles_to "\xF3\xAB", :rep_stosd
170
+ assert_assembles_to "\xF3\x48\xAB", :rep_stosq
171
+ end
172
+
173
+ def test_nop
174
+ assert_assembles_to "\x66\x0F\x1F\xC0", :nop_rm16, reg0: :a
175
+ assert_assembles_to "\x0F\x1F\xC0", :nop_rm32, reg0: :a
176
+ end
177
+
178
+ def test_movq_mm
179
+ assert_assembles_to "\x48\x0F\x6E\xC0", :movq_mm_rm64, reg0: :mm0, reg1: :a
180
+ assert_assembles_to "\x48\x0F\x6E\x00", :movq_mm_rm64, reg0: :mm0, reg_base: :a
181
+ end
182
+
183
+ def test_movd_mm
184
+ assert_assembles_to "\x0F\x6E\xC0", :movd_mm_rm32, reg0: :mm0, reg1: :a
185
+ assert_assembles_to "\x0F\x6E\x00", :movd_mm_rm32, reg0: :mm0, reg_base: :a
186
+ end
187
+
188
+ def test_movq_xmm
189
+ assert_assembles_to "\x66\x48\x0F\x6E\xC0", :movq_xmm_rm64, reg0: :xmm0, reg1: :a
190
+ assert_assembles_to "\x66\x49\x0F\x6E\xC4", :movq_xmm_rm64, reg0: :xmm0, reg1: :r12
191
+ assert_assembles_to "\x66\x4D\x0F\x6E\xE4", :movq_xmm_rm64, reg0: :xmm12, reg1: :r12
192
+
193
+ assert_assembles_to "\x66\x4D\x0F\x6E\x24\x24", :movq_xmm_rm64, reg0: :xmm12, reg_base: :r12
194
+ end
195
+
196
+ def test_vmovq
197
+ assert_assembles_to "\xC4\xE1\xF9\x6E\xC0", :vmovq_xmm_rm64, reg0: :xmm0, reg1: :a
198
+ assert_assembles_to "\xC4\xC1\xF9\x6E\xC4", :vmovq_xmm_rm64, reg0: :xmm0, reg1: :r12
199
+ assert_assembles_to "\xC4\x41\xF9\x6E\xE4", :vmovq_xmm_rm64, reg0: :xmm12, reg1: :r12
200
+ assert_assembles_to "\xC4\x41\xF9\x6E\x24\x24", :vmovq_xmm_rm64, reg0: :xmm12, reg_base: :r12
201
+
202
+ assert_assembles_to "\xC4\xE1\xF9\x7E\xC0", :vmovq_rm64_xmm, reg0: :a, reg1: :xmm0
203
+ assert_assembles_to "\xC4\xC1\xF9\x7E\xC4", :vmovq_rm64_xmm, reg0: :r12, reg1: :xmm0
204
+ assert_assembles_to "\xC4\x41\xF9\x7E\xE4", :vmovq_rm64_xmm, reg0: :r12, reg1: :xmm12
205
+ assert_assembles_to "\xC4\x41\xF9\x7E\x24\x24", :vmovq_rm64_xmm, reg_base: :r12, reg1: :xmm12
206
+ end
207
+
208
+ def test_movd_xmm
209
+ assert_assembles_to "\x66\x0F\x6E\xC0", :movd_xmm_rm32, reg0: :xmm0, reg1: :a
210
+ assert_assembles_to "\x66\x41\x0F\x6E\xC4", :movd_xmm_rm32, reg0: :xmm0, reg1: :r12
211
+ assert_assembles_to "\x66\x45\x0F\x6E\xE4", :movd_xmm_rm32, reg0: :xmm12, reg1: :r12
212
+
213
+ assert_assembles_to "\x66\x45\x0F\x6E\x24\x24", :movd_xmm_rm32, reg0: :xmm12, reg_base: :r12
214
+ end
215
+
216
+ def test_xchg_implicit
217
+ assert_assembles_to "\x66\x93", :xchg_ax_r16, reg0: :b
218
+ assert_assembles_to "\x93", :xchg_eax_r32, reg0: :b
219
+ assert_assembles_to "\x48\x93", :xchg_rax_r64, reg0: :b
220
+ end
221
+
222
+ def test_prefetchwt1
223
+ assert_assembles_to "\x0F\x0D\x10", :prefetchwt1_m8, reg_base: :a
224
+ assert_assembles_to "\x67\x0F\x0D\x10", :prefetchwt1_m8, reg_base: :a, addr_size: 32
225
+ end
226
+
227
+ def test_lea_rip
228
+ assert_disassembles_to 'lea rax, qword ptr [rip]', :lea_r64_m64, reg0: :a, reg_base: :ip
229
+ end
230
+
231
+ SIMD_CMP_INSTRUCTION_NAMES = %i(
232
+ vcmpps_xmm_xmm_xmmm128_imm8
233
+ vcmppd_xmm_xmm_xmmm128_imm8
234
+ vcmpps_ymm_ymm_ymmm256_imm8
235
+ vcmppd_ymm_ymm_ymmm256_imm8
236
+ vcmpsd_xmm_xmm_xmmm64_imm8
237
+ vcmpss_xmm_xmm_xmmm32_imm8
238
+ cmpps_xmm_xmmm128_imm8
239
+ cmppd_xmm_xmmm128_imm8
240
+ cmpsd_xmm_xmmm64_imm8
241
+ cmpss_xmm_xmmm32_imm8
242
+ ).freeze
243
+
244
+ NOP_INSTRUCTION_NAMES = %i(
245
+ nop_rm16
246
+ nop_rm32
247
+ ).freeze
248
+
249
+ XCHG_IMPLICIT_INSTRUCTION_NAMES = %i(
250
+ xchg_ax_r16
251
+ xchg_eax_r32
252
+ xchg_rax_r64
253
+ ).freeze
254
+
255
+ STRING_INSTRUCTION_NAMES = %i(
256
+ cmpsb
257
+ cmpsw
258
+ cmpsd
259
+ cmpsq
260
+ repe_cmpsb
261
+ repe_cmpsw
262
+ repe_cmpsd
263
+ repe_cmpsq
264
+ repne_cmpsb
265
+ repne_cmpsw
266
+ repne_cmpsd
267
+ repne_cmpsq
268
+ lodsb
269
+ lodsw
270
+ lodsd
271
+ lodsq
272
+ rep_lodsb
273
+ rep_lodsw
274
+ rep_lodsd
275
+ rep_lodsq
276
+ movsb
277
+ movsw
278
+ movsd
279
+ movsq
280
+ rep_movsb
281
+ rep_movsw
282
+ rep_movsd
283
+ rep_movsq
284
+ scasb
285
+ scasw
286
+ scasd
287
+ scasq
288
+ repe_scasb
289
+ repe_scasw
290
+ repe_scasd
291
+ repe_scasq
292
+ repne_scasb
293
+ repne_scasw
294
+ repne_scasd
295
+ repne_scasq
296
+ stosb
297
+ stosw
298
+ stosd
299
+ stosq
300
+ rep_stosb
301
+ rep_stosw
302
+ rep_stosd
303
+ rep_stosq
304
+ ).freeze
305
+
306
+ MOVQ_MOVD_INSTRUCTION_NAMES = %i(
307
+ movq_mm_rm64
308
+ movq_rm64_mm
309
+ movd_mm_rm32
310
+ movd_rm32_mm
311
+ movq_xmm_rm64
312
+ movq_rm64_xmm
313
+ movd_xmm_rm32
314
+ movd_rm32_xmm
315
+ vmovq_xmm_rm64
316
+ vmovq_rm64_xmm
317
+ ).freeze
318
+
319
+ UNSUPPORTED_INSTRUCTION_NAMES = %i(
320
+ prefetchwt1_m8
321
+ rdpid_r64
322
+ )
323
+
324
+ class InstructionTest
325
+ attr_reader :instruction
326
+
327
+ class ActualOperand
328
+
329
+ REGISTERS = {
330
+ a: {
331
+ 8 => 'al',
332
+ 16 => 'ax',
333
+ 32 => 'eax',
334
+ 64 => 'rax'
335
+ },
336
+ b: {
337
+ 8 => 'bl',
338
+ 16 => 'bx',
339
+ 32 => 'ebx',
340
+ 64 => 'rbx'
341
+ },
342
+ c: {
343
+ 8 => 'cl',
344
+ 16 => 'cx',
345
+ 32 => 'ecx',
346
+ 64 => 'rcx'
347
+ },
348
+ bp: {
349
+ 8 => 'bpl',
350
+ 16 => 'bp',
351
+ 32 => 'ebp',
352
+ 64 => 'rbp'
353
+ },
354
+ sp: {
355
+ 8 => 'spl',
356
+ 16 => 'sp',
357
+ 32 => 'esp',
358
+ 64 => 'rsp'
359
+ },
360
+ r11: {
361
+ 8 => 'r11b',
362
+ 16 => 'r11w',
363
+ 32 => 'r11d',
364
+ 64 => 'r11'
365
+ },
366
+ r12: {
367
+ 8 => 'r12b',
368
+ 16 => 'r12w',
369
+ 32 => 'r12d',
370
+ 64 => 'r12'
371
+ },
372
+ xmm0: {
373
+ 128 => 'xmm0',
374
+ 256 => 'ymm0'
375
+ },
376
+ xmm1: {
377
+ 128 => 'xmm1',
378
+ 256 => 'ymm1'
379
+ },
380
+ xmm2: {
381
+ 128 => 'xmm2',
382
+ 256 => 'ymm2'
383
+ },
384
+ xmm3: {
385
+ 128 => 'xmm3',
386
+ 256 => 'ymm3'
387
+ },
388
+ xmm10: {
389
+ 128 => 'xmm10',
390
+ 256 => 'ymm10'
391
+ },
392
+ xmm11: {
393
+ 128 => 'xmm11',
394
+ 256 => 'ymm11'
395
+ },
396
+ mm0: {
397
+ 64 => 'mm0'
398
+ },
399
+ mm1: {
400
+ 64 => 'mm1'
401
+ },
402
+ mm7: {
403
+ 64 => 'mm7'
404
+ }
405
+ }.freeze
406
+
407
+ attr_reader :parameter_names
408
+ attr_reader :parameter_values
409
+ attr_reader :type, :size
410
+
411
+ def initialize(type, parameter_names, parameter_values, size = nil, register_size = nil)
412
+ @type = type
413
+ @parameter_names = Array(parameter_names)
414
+ @parameter_values = Array(parameter_values)
415
+ @size = size
416
+ @register_size = register_size
417
+ end
418
+
419
+ def parameter_name
420
+ @parameter_names.first
421
+ end
422
+
423
+ def parameter_value
424
+ @parameter_values.first
425
+ end
426
+
427
+ def disassembly(encoded_instruction = nil)
428
+ send :"#{type}_disassembly", encoded_instruction
429
+ end
430
+
431
+ private
432
+
433
+ def imm_disassembly(encoded_instruction)
434
+ value = parameter_value
435
+ value += encoded_instruction.bytesize if parameter_name == :rel
436
+
437
+ if value == 1
438
+ value.to_s
439
+ else
440
+ "0x#{value.to_s(16)}"
441
+ end
442
+ end
443
+
444
+ def reg_disassembly(encoded_instruction)
445
+ REGISTERS.fetch(parameter_value).fetch(size)
446
+ end
447
+
448
+ def mem_disassembly(encoded_instruction)
449
+ pointer =
450
+ if parameter_name == :moffs
451
+ "0x#{parameter_value.to_s(16)}"
452
+ else
453
+
454
+ base_register, index_register =
455
+ REGISTERS.values_at(*parameter_values.values_at(0, 1)).map do |sizes|
456
+ next nil if sizes.nil?
457
+ if sizes.key? 64
458
+ sizes[64]
459
+ else
460
+ sizes[@register_size]
461
+ end
462
+ end
463
+
464
+ scale = parameter_values[2]
465
+
466
+ sib = ''
467
+ sib << base_register
468
+ sib << " + #{index_register}" if index_register
469
+ sib << "*#{scale}" if scale && scale != 1
470
+
471
+ sib
472
+ end
473
+
474
+ "#{pointer_size} ptr [#{pointer}]"
475
+ end
476
+
477
+ def pointer_size
478
+ case size
479
+ when 8
480
+ 'byte'
481
+ when 16
482
+ 'word'
483
+ when 32
484
+ 'dword'
485
+ when 64
486
+ 'qword'
487
+ when 128
488
+ 'xmmword'
489
+ when 256
490
+ 'ymmword'
491
+ when nil
492
+ ''
493
+ else
494
+ raise "invalid pointer size #{size}"
495
+ end
496
+ end
497
+
498
+ end
499
+
500
+ class ActualOperands
501
+ attr_reader :formal_operand
502
+
503
+ REGISTERS = {
504
+ gp: %i(a c b sp bp r11 r12),
505
+ xmm: %i(xmm0 xmm1 xmm10 xmm11),
506
+ mm: %i(mm0 mm1 mm7)
507
+ }.freeze
508
+
509
+ SKIP_IMPLICIT_XMM0_INSTRUCTION_NAMES = %i(
510
+ blendvpd_xmm_xmmm128_xmm0
511
+ blendvps_xmm_xmmm128_xmm0
512
+ pblendvb_xmm_xmmm128_xmm0
513
+ sha256rnds2_xmm_xmmm128_xmm0
514
+ ).freeze
515
+
516
+ IMMEDIATE_VALUES = {
517
+ imm: 0x4a,
518
+ imm0: 0x4a,
519
+ imm1: 0x4b,
520
+ rel: 0x4c,
521
+ moffs: 0x4d,
522
+ }.freeze
523
+
524
+ def initialize(formal_operand, basic:)
525
+ @formal_operand = formal_operand
526
+ @actual_operands = []
527
+ @basic = basic
528
+
529
+ load
530
+ end
531
+
532
+ def basic?
533
+ @basic
534
+ end
535
+
536
+ def parameter_name
537
+ formal_operand.parameter&.name
538
+ end
539
+
540
+ def to_a
541
+ @actual_operands
542
+ end
543
+
544
+ def empty?
545
+ @actual_operands.empty?
546
+ end
547
+
548
+ private
549
+
550
+ def load
551
+ if formal_operand.mnemonic?
552
+ case formal_operand.type
553
+ when :reg
554
+ add_register_operand
555
+ when :rm
556
+ add_register_operand
557
+ add_memory_operand unless basic?
558
+ when :imm
559
+ add_immediate_operand
560
+ when :mem
561
+ add_memory_operand
562
+ when :vsib
563
+ raise if basic?
564
+ add_vsib_operand
565
+ else
566
+ raise "unknown operand type #{formal_operand.type}"
567
+ end
568
+ end
569
+ end
570
+
571
+ def add_register_operand
572
+ if formal_operand.implicit?
573
+ register = formal_operand.register
574
+ unless register == :xmm0 && skip_implicit_xmm0?
575
+ @actual_operands << ActualOperand.new(:reg, nil,
576
+ formal_operand.register,
577
+ formal_operand.size)
578
+ end
579
+ else
580
+ raise 'missing parameter' unless formal_operand.parameter
581
+ REGISTERS.fetch(formal_operand.register_type).each do |register|
582
+ @actual_operands << ActualOperand.new(:reg, parameter_name,
583
+ register, formal_operand.size)
584
+ end
585
+ end
586
+ end
587
+
588
+ def add_memory_operand
589
+ if parameter_name == :moffs
590
+ @actual_operands << ActualOperand.new(:mem,
591
+ parameter_name,
592
+ IMMEDIATE_VALUES.fetch(parameter_name),
593
+ memory_size)
594
+ else
595
+ REGISTERS.fetch(:gp).each do |register|
596
+ @actual_operands << ActualOperand.new(:mem,
597
+ [:reg_base],
598
+ [register],
599
+ memory_size)
600
+ end
601
+ end
602
+ end
603
+
604
+ def add_vsib_operand
605
+ @actual_operands << ActualOperand.new(:mem,
606
+ [:reg_base, :reg_index, :scale],
607
+ [:a, :xmm0, 1],
608
+ memory_size,
609
+ formal_operand.index_register_size)
610
+ end
611
+
612
+ def add_immediate_operand
613
+ @actual_operands <<
614
+ if formal_operand.implicit?
615
+ ActualOperand.new(:imm, parameter_name, formal_operand.immediate)
616
+ else
617
+ ActualOperand.new(:imm, parameter_name, IMMEDIATE_VALUES.fetch(parameter_name))
618
+ end
619
+ end
620
+
621
+ def skip_implicit_xmm0?
622
+ SKIP_IMPLICIT_XMM0_INSTRUCTION_NAMES.include? formal_operand.instruction.name
623
+ end
624
+
625
+ def memory_size
626
+ # Work around bugs in Capstone
627
+ # which sometimes reports wrong pointer sizes
628
+ # FIXME: recheck if we really got them right
629
+ case formal_operand.instruction.name
630
+ when :comisd_xmm_xmmm64
631
+ 128
632
+ when :comiss_xmm_xmmm32
633
+ 128
634
+ when :punpcklbw_mm_mmm32,
635
+ :punpckldq_mm_mmm32,
636
+ :punpcklwd_mm_mmm32
637
+ 64
638
+ when :vcomisd_xmm_xmmm64,
639
+ :vcomisd_xmm_xmmm32,
640
+ :vcomiss_xmm_xmmm32
641
+ 128
642
+ when :vpmovsxbd_ymm_xmmm64,
643
+ :vpmovsxwq_ymm_xmmm64,
644
+ :vpmovsxbd_ymm_xmmm64,
645
+ :vpmovzxbd_ymm_xmmm64,
646
+ :vpmovzxwq_ymm_xmmm64
647
+ 32
648
+ when :vpmovsxbq_ymm_xmmm32,
649
+ :vpmovzxbq_ymm_xmmm32
650
+ 16
651
+ else
652
+ formal_operand.memory_size
653
+ end
654
+ end
655
+ end
656
+
657
+ def test_rdpid
658
+ skip 'missing'
659
+ end
660
+
661
+ def initialize(test_class, instruction)
662
+ @test_class = test_class
663
+ @instruction = instruction
664
+ end
665
+
666
+ def mnemonics
667
+ case instruction.name
668
+ when :clflushopt_m8
669
+ # Capstone, might be a bug
670
+ %w(clflush)
671
+ when :vcvtpd2dq_xmm_xmmm128
672
+ %w(vcvtpd2dqx vcvtpd2dq)
673
+ when :vcvtpd2ps_xmm_xmmm128
674
+ %w(vcvtpd2ps vcvtpd2psx)
675
+ when :vcvttpd2dq_xmm_xmmm128
676
+ %w(vcvttpd2dqx vcvttpd2dq)
677
+ else
678
+ instruction.mnemonics
679
+ end
680
+ end
681
+
682
+ def run(test, basic:)
683
+ return if basic && !instruction.basic?
684
+
685
+ # Capstone prints rm operand last
686
+ operands = instruction.operands.map do |operand|
687
+ ActualOperands.new operand, basic: basic
688
+ end.reject(&:empty?)
689
+
690
+ combinations =
691
+ if operands.empty?
692
+ [[]]
693
+ else
694
+ combinations =
695
+ operands.first.to_a.product(*(operands[1..-1] || []).map(&:to_a))
696
+ end
697
+
698
+ raise if combinations.empty?
699
+ combinations.each do |combination|
700
+ parameters = Evoasm::X64::Parameters.new(basic: basic)
701
+ combination.each do |operand|
702
+ operand.parameter_names.zip(operand.parameter_values) do |name, value|
703
+ parameters[name] = value
704
+ test.assert_equal value, parameters[name]
705
+ end
706
+ end
707
+
708
+ encoded_instruction = instruction.encode parameters, basic: basic
709
+
710
+ # Capstone gives operands in wrong order
711
+ # Oddly, only if both operands are registers
712
+ if instruction.name =~ /^test_rm\d+_r\d+/ &&
713
+ combination.all? { |operand| operand.type == :reg }
714
+ combination.reverse!
715
+ end
716
+
717
+ operands_disassembly = combination.map do |operand|
718
+ operand.disassembly encoded_instruction
719
+ end
720
+
721
+ expected_disassemblys = mnemonics.map do |mnemonic|
722
+ "#{mnemonic.downcase} #{operands_disassembly.join(', ')}"
723
+ end
724
+
725
+ test.assert_includes expected_disassemblys, test.disassemble(encoded_instruction)
726
+ end
727
+ end
728
+
729
+ def define!(basic:)
730
+ run_method = method(:run)
731
+
732
+ @test_class.send :define_method, test_method_name(basic: basic) do
733
+ run_method.call self, basic: basic
734
+ end
735
+ end
736
+
737
+ private
738
+
739
+ def test_method_name(basic:)
740
+ method_name = "test_#{instruction.name}"
741
+ method_name << '_basic' if basic
742
+
743
+ method_name
744
+ end
745
+ end
746
+
747
+ Evoasm::Libevoasm.enum_type(:x64_inst_id).symbols.each do |instruction_name|
748
+ next if instruction_name == :none
749
+ # Capstone uses pseudo-mnemonics, tested separately
750
+ next if SIMD_CMP_INSTRUCTION_NAMES.include? instruction_name
751
+
752
+ # Capstone does not like these for some reason, test separately
753
+ next if NOP_INSTRUCTION_NAMES.include? instruction_name
754
+ next if XCHG_IMPLICIT_INSTRUCTION_NAMES.include? instruction_name
755
+
756
+ # Capstone gives implicit operands for these
757
+ next if STRING_INSTRUCTION_NAMES.include? instruction_name
758
+
759
+ # Most (dis)assemblers (including Capstone) use the MOVD mnemonic for both
760
+ # movq and movd, and MOVQ (but sometimes also MOVD) for the XMM version.
761
+ # Oddly, GNU AS correctly uses the MM version if movq
762
+ # is used with register operands but does use the XMM version
763
+ # for SIB operands.
764
+ # Anyway, Capstone does not get this 100% right, or at least not
765
+ # how we need it.
766
+ next if MOVQ_MOVD_INSTRUCTION_NAMES.include? instruction_name
767
+
768
+ # not supported by Capstone
769
+ next if UNSUPPORTED_INSTRUCTION_NAMES.include? instruction_name
770
+
771
+
772
+ instruction = Evoasm::X64.instruction instruction_name
773
+ instruction_test = InstructionTest.new self, instruction
774
+
775
+ instruction_test.define! basic: false
776
+ instruction_test.define! basic: true
777
+ end
778
+ end
779
+ end
780
+ end