evoasm 0.0.2.pre7 → 0.1.0.pre2

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