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,106 @@
1
+ require 'evoasm/test'
2
+ require 'evoasm/population/parameters'
3
+
4
+ module Evoasm
5
+ class Population
6
+ class ParametersTest < Minitest::Test
7
+
8
+ def setup
9
+ @parameters = Evoasm::Population::Parameters.new :x64
10
+ end
11
+
12
+ def test_mutation_rate
13
+ @parameters.mutation_rate = 0.001
14
+ assert_in_epsilon 0.001, @parameters.mutation_rate, 0.0001
15
+
16
+ @parameters.mutation_rate = 0.5
17
+ assert_in_epsilon 0.5, @parameters.mutation_rate, 0.0001
18
+ end
19
+
20
+ def test_deme_size
21
+ @parameters.deme_size = 100
22
+ assert_equal 100, @parameters.deme_size
23
+ end
24
+
25
+ def test_deme_count
26
+ @parameters.deme_count = 12
27
+ assert_equal 12, @parameters.deme_count
28
+ end
29
+
30
+ def test_validate!
31
+ error = assert_raises Evoasm::Error do
32
+ @parameters.validate!
33
+ end
34
+
35
+ # while at it, let's test Error
36
+ assert_equal :pop_params, error.type
37
+ assert_kind_of Integer, error.line
38
+ assert_match /pop-params/, error.filename
39
+ end
40
+
41
+ def test_kernel_size
42
+ @parameters.kernel_size = 10
43
+ assert_equal 10, @parameters.kernel_size
44
+ end
45
+
46
+ def test_program_size
47
+ @parameters.program_size = 4
48
+ assert_equal 4, @parameters.program_size
49
+ end
50
+
51
+ def test_recur_limit
52
+ @parameters.recur_limit = 1000
53
+ assert_equal 1000, @parameters.recur_limit
54
+ end
55
+
56
+ def test_examples
57
+ examples = {
58
+ [0, 1] => 0,
59
+ [1, 0] => 100,
60
+ [3, 5] => 10000
61
+ }
62
+ @parameters.examples = examples
63
+ assert_equal examples, @parameters.examples
64
+ end
65
+
66
+ def test_parameters
67
+ parameters = %i(reg0 reg1 reg2)
68
+ @parameters.parameters = parameters
69
+ assert_equal parameters, @parameters.parameters
70
+
71
+ parameters = %i(does not exist)
72
+ assert_raises do
73
+ @parameters.parameters = parameters
74
+ end
75
+ end
76
+
77
+ def test_domains
78
+ domains = {
79
+ reg0: [:a, :c, :b],
80
+ reg1: [:r11, :r12, :r13],
81
+ imm0: (0..10)
82
+ }
83
+
84
+ # must set parameter before setting domain
85
+ assert_raises ArgumentError do
86
+ @parameters.domains = domains
87
+ end
88
+
89
+ @parameters.parameters = %i(reg0 reg1 imm0)
90
+ @parameters.domains = domains
91
+
92
+ assert_kind_of Evoasm::EnumerationDomain, @parameters.domains[:reg0]
93
+ assert_kind_of Evoasm::RangeDomain, @parameters.domains[:imm0]
94
+ assert_equal 0, @parameters.domains[:imm0].min
95
+ assert_equal 10, @parameters.domains[:imm0].max
96
+ end
97
+
98
+ def test_instructions
99
+ instructions = %i(adc_al_imm8 adc_rm8_r8)
100
+ @parameters.instructions = instructions
101
+
102
+ assert_equal instructions, @parameters.instructions
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,96 @@
1
+ require 'evoasm/test'
2
+ require 'evoasm/population'
3
+ require 'population_helper'
4
+
5
+ module Evoasm
6
+ class PopulationTest < Minitest::Test
7
+ include PopulationHelper
8
+
9
+ def setup
10
+ set_default_parameters
11
+ @kernel_size = 2
12
+ @program_size = 1
13
+ end
14
+
15
+ def test_unseeded
16
+ error = assert_raises Evoasm::Error do
17
+ deme = new_population
18
+ deme.evaluate { |_, _|}
19
+ end
20
+
21
+ assert_match /seed/, error.message
22
+ end
23
+
24
+ def test_no_error
25
+ start
26
+ end
27
+
28
+ def test_find_median
29
+ [8, 16].each do |size|
30
+ ary = Array.new(size) { rand(0..1000) }
31
+ median = ary.sort.at((ary.size / 2) - 1)
32
+
33
+ p ary.sort
34
+
35
+ data_ptr = FFI::MemoryPointer.new :float, ary.size
36
+ data_ptr.write_array_of_float ary
37
+ assert_equal median, Libevoasm.pop_find_median_loss(data_ptr, ary.size)
38
+ end
39
+ end
40
+
41
+ def test_no_instructions
42
+ @instruction_names = []
43
+ error = assert_raises Evoasm::Error do
44
+ start
45
+ end
46
+
47
+ assert_match /instructions/, error.message
48
+ end
49
+
50
+ def test_no_parameters
51
+ @parameters = []
52
+ error = assert_raises Evoasm::Error do
53
+ start
54
+ end
55
+
56
+ assert_match /parameters/, error.message
57
+ end
58
+
59
+ def test_no_examples
60
+ @examples = {}
61
+ error = assert_raises Evoasm::Error do
62
+ start
63
+ end
64
+
65
+ assert_match /input|output/, error.message
66
+ end
67
+
68
+ def test_invalid_deme_size
69
+ @deme_size = 0
70
+ error = assert_raises Evoasm::Error do
71
+ start
72
+ end
73
+ assert_match /deme size/i, error.message
74
+ end
75
+
76
+ def test_invalid_program_size
77
+ [0, 2**32].each do |program_size|
78
+ @program_size = program_size
79
+ error = assert_raises Evoasm::Error do
80
+ start
81
+ end
82
+ assert_match /program size/i, error.message
83
+ end
84
+ end
85
+
86
+ def test_invalid_kernel_size
87
+ [0, 2**32].each do |kernel_size|
88
+ @kernel_size = kernel_size
89
+ error = assert_raises Evoasm::Error do
90
+ start
91
+ end
92
+ assert_match /kernel size/i, error.message
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,47 @@
1
+ require 'evoasm/test'
2
+ require 'evoasm/prng'
3
+
4
+ module Evoasm
5
+ class PRNGTest < Minitest::Test
6
+ def setup
7
+ @prng = Evoasm::PRNG.new
8
+ end
9
+
10
+ def test_same_seed
11
+ same_prng = Evoasm::PRNG.new
12
+
13
+ 10.times do
14
+ assert_equal @prng.rand64, same_prng.rand64
15
+ end
16
+ end
17
+
18
+ def test_different_seed
19
+ other_prng = Evoasm::PRNG.new (11..26).to_a
20
+
21
+ refute_equal @prng.rand64, other_prng.rand64
22
+ end
23
+
24
+ def test_rand8
25
+ buckets = Array.new(256, 0)
26
+ sample_size = 100_000
27
+ sample_size.times do
28
+ r = @prng.rand8
29
+ refute_operator r, :>, 255
30
+ refute_operator r, :<, 0
31
+ buckets[r] += 1
32
+ end
33
+
34
+ # Not sufficient,
35
+ # but indicates if something is seriously wrong
36
+ exp_bucket_size = sample_size / buckets.size
37
+ mse = 1.0/buckets.size * buckets.inject(0) do |acc, sample|
38
+ diff = ((sample - exp_bucket_size.to_f)**2 / exp_bucket_size.to_f)
39
+ p [sample, exp_bucket_size, diff]
40
+ acc + diff
41
+ end
42
+
43
+ rmse = Math.sqrt mse
44
+ assert_operator rmse, :<, 2.0
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,73 @@
1
+ require 'evoasm/test'
2
+ require 'evoasm/x64/cpu_state'
3
+ require 'evoasm/buffer'
4
+
5
+ module Evoasm
6
+ module X64
7
+ class CPUStateTest < Minitest::Test
8
+ def setup
9
+ @cpu_state = CPUState.new
10
+ end
11
+
12
+ def test_clean
13
+ X64.registers.each do |reg|
14
+ data = @cpu_state[reg]
15
+ refute_empty data
16
+ assert data.all? { |e| e == 0 }
17
+ end
18
+ end
19
+
20
+ def test_set_get
21
+ @cpu_state[:a] = 0xFF
22
+ assert_equal [0xFF], @cpu_state[:a]
23
+
24
+ @cpu_state[:b] = [0xDEADBEEF]
25
+ assert_equal [0xDEADBEEF], @cpu_state[:b]
26
+
27
+ # FIXME: with AVX512 the array
28
+ # should be of size 8
29
+ data = (1..4).to_a
30
+ @cpu_state[:xmm0] = data
31
+ assert_equal data, @cpu_state[:xmm0]
32
+ end
33
+
34
+ def test_clone
35
+ @cpu_state[:b] = 0xFAB
36
+ cloned_cpu_state = @cpu_state.clone
37
+
38
+ assert_equal [0xFAB], cloned_cpu_state[:b]
39
+ end
40
+
41
+ def test_emit_store
42
+ buffer = Buffer.new 1024
43
+ Evoasm::X64.encode(:mov_rm32_imm32, {reg0: :a, imm0: 7}, buffer)
44
+
45
+ @cpu_state.emit_store buffer
46
+ Evoasm::X64.encode(:ret, {}, buffer)
47
+
48
+ buffer.execute!
49
+ assert_equal [7], @cpu_state[:a]
50
+ end
51
+
52
+ def test_emit_load
53
+ buffer = Buffer.new 1024
54
+
55
+ @cpu_state[:a] = 0xABCD
56
+ @cpu_state[:rflags] = [0x1]
57
+
58
+ cpu_state_after = CPUState.new
59
+
60
+ X64.emit_stack_frame buffer do
61
+ @cpu_state.emit_load buffer
62
+ cpu_state_after.emit_store buffer
63
+ end
64
+
65
+ #buffer.__log__ :warn
66
+ buffer.execute!
67
+
68
+ assert_equal [0xABCD], cpu_state_after[:a]
69
+ assert_equal [0x1], cpu_state_after[:rflags]
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,320 @@
1
+ require 'evoasm/test'
2
+
3
+ require 'x64_helper'
4
+
5
+ module Evoasm
6
+ module X64
7
+ class EncodingTest < Minitest::Test
8
+ include X64Helper
9
+
10
+ def test_direct
11
+ assert_disassembles_to 'add rax, rbx', :add_r64_rm64,
12
+ reg0: :a, reg1: :b
13
+ assert_disassembles_to 'add rax, r12', :add_r64_rm64,
14
+ reg0: :a, reg1: :r12
15
+ assert_disassembles_to 'add r11, rbx', :add_r64_rm64,
16
+ reg0: :r11, reg1: :b
17
+ assert_disassembles_to 'add r11, r12', :add_r64_rm64,
18
+ reg0: :r11, reg1: :r12
19
+
20
+ assert_disassembles_to 'add eax, ebx', :add_r32_rm32,
21
+ reg0: :a, reg1: :b
22
+ assert_disassembles_to 'add eax, r12d', :add_r32_rm32,
23
+ reg0: :a, reg1: :r12
24
+ assert_disassembles_to 'add r11d, ebx', :add_r32_rm32,
25
+ reg0: :r11, reg1: :b
26
+ assert_disassembles_to 'add r11d, r12d', :add_r32_rm32,
27
+ reg0: :r11, reg1: :r12
28
+
29
+ assert_disassembles_to 'add ax, bx', :add_r16_rm16,
30
+ reg0: :a, reg1: :b
31
+ assert_disassembles_to 'add ax, r12w', :add_r16_rm16,
32
+ reg0: :a, reg1: :r12
33
+ assert_disassembles_to 'add r11w, bx', :add_r16_rm16,
34
+ reg0: :r11, reg1: :b
35
+ assert_disassembles_to 'add r11w, r12w', :add_r16_rm16,
36
+ reg0: :r11, reg1: :r12
37
+
38
+ end
39
+
40
+ def test_indirect
41
+ assert_disassembles_to 'add rax, qword ptr [rbx]', :add_r64_rm64,
42
+ reg0: :a, reg_base: :b
43
+ assert_disassembles_to 'add r11, qword ptr [r12]', :add_r64_rm64,
44
+ reg0: :r11, reg_base: :r12
45
+ assert_disassembles_to 'add eax, dword ptr [rbx]', :add_r32_rm32,
46
+ reg0: :a, reg_base: :b
47
+ assert_disassembles_to 'add ax, word ptr [rbx]', :add_r16_rm16,
48
+ reg0: :a, reg_base: :b
49
+
50
+ # reg1 should be ignored
51
+ assert_disassembles_to 'add eax, dword ptr [rbx]', :add_r32_rm32,
52
+ reg0: :a, reg1: :c, reg_base: :b
53
+
54
+ assert_disassembles_to 'add rax, qword ptr [rbx + rcx*4]', :add_r64_rm64,
55
+ reg0: :a, reg_base: :b, reg_index: :c, scale: 4
56
+ assert_disassembles_to 'add rax, qword ptr [rbx + rcx]', :add_r64_rm64,
57
+ reg0: :a, reg_base: :b, reg_index: :c, scale: 1
58
+ assert_disassembles_to 'add rax, qword ptr [rbx + rcx*8]', :add_r64_rm64,
59
+ reg0: :a, reg_base: :b, reg_index: :c, scale: 8
60
+ assert_disassembles_to 'add r10, qword ptr [r11 + r12*4]', :add_r64_rm64,
61
+ reg0: :r10, reg_base: :r11, reg_index: :r12, scale: 4
62
+
63
+
64
+ # Force SIB
65
+ with_forced_sib = assemble :add_r64_rm64,
66
+ reg0: :r10, reg_base: :r11,
67
+ force_sib?: true
68
+
69
+ without_forced_sib = assemble :add_r64_rm64,
70
+ reg0: :r10, reg_base: :r11,
71
+ force_sib?: false
72
+
73
+ refute_equal with_forced_sib, without_forced_sib
74
+
75
+ assert_equal 'add r10, qword ptr [r11]', disassemble(with_forced_sib)
76
+ assert_equal 'add r10, qword ptr [r11]', disassemble(without_forced_sib)
77
+
78
+ # SP/R12 always need SIB
79
+ {sp: 'rsp', r12: 'r12'}.each do |reg_base, reg_base_name|
80
+
81
+ with_forced_sib = assemble(:add_r64_rm64,
82
+ reg0: :r10,
83
+ reg_base: reg_base,
84
+ force_sib?: true)
85
+
86
+ without_forced_sib = assemble(:add_r64_rm64,
87
+ reg0: :r10,
88
+ reg_base: reg_base,
89
+ force_sib?: false)
90
+
91
+ assert_equal with_forced_sib, without_forced_sib
92
+
93
+ assert_equal "add r10, qword ptr [#{reg_base_name}]",
94
+ disassemble(with_forced_sib)
95
+
96
+ assert_equal "add r10, qword ptr [#{reg_base_name}]",
97
+ disassemble(without_forced_sib)
98
+ end
99
+
100
+ # Force 32-bit displacement
101
+ with_disp8 = assemble :add_r64_rm64,
102
+ reg0: :r10, reg_base: :r11, disp: 0x10
103
+
104
+ with_disp32 = assemble :add_r64_rm64,
105
+ reg0: :r10, reg_base: :r11, disp: 0x10, force_disp32?: true
106
+
107
+ assert_equal 'add r10, qword ptr [r11 + 0x10]', disassemble(with_disp8)
108
+ assert_equal 'add r10, qword ptr [r11 + 0x10]', disassemble(with_disp32)
109
+
110
+ refute_equal with_disp8, with_disp32
111
+ end
112
+
113
+ def test_address_size
114
+ assert_disassembles_to 'add rax, dword ptr [ebx]', :add_r64_rm64,
115
+ reg0: :a, reg_base: :b, addr_size: 32
116
+
117
+ assert_disassembles_to 'add eax, dword ptr [ebx]', :add_r32_rm32,
118
+ reg0: :a, reg_base: :b, addr_size: 32
119
+ end
120
+
121
+ def test_lock
122
+ assert_disassembles_to 'lock add qword ptr [rax], rbx', :add_rm64_r64,
123
+ reg_base: :a, reg1: :b, lock?: true
124
+
125
+ assert_disassembles_to 'lock inc qword ptr [r10]', :inc_rm64,
126
+ reg_base: :r10, lock?: true
127
+ end
128
+
129
+ def test_rex
130
+ assert_disassembles_to 'add rax, rbx', :add_r64_rm64,
131
+ reg0: :a, reg1: :b, force_rex?: true
132
+
133
+ # needs REX (.W), even if not forced
134
+ assert_assembles_to "\x48\x03\xC3", :add_r64_rm64,
135
+ reg0: :a, reg1: :b, force_rex?: false
136
+
137
+ assert_assembles_to "\x48\x03\xC3", :add_r64_rm64,
138
+ reg0: :a, reg1: :b, force_rex?: true
139
+
140
+ # REX.X is free
141
+ assert_assembles_to "\x4A\x03\xC3", :add_r64_rm64,
142
+ reg0: :a, reg1: :b, rex_x: 0b1
143
+
144
+ assert_disassembles_to 'add rax, rbx', :add_r64_rm64,
145
+ reg0: :a, reg1: :b, rex_x: 0b1
146
+
147
+ # REX is optional
148
+ assert_disassembles_to 'add eax, ebx', :add_r32_rm32,
149
+ reg0: :a, reg1: :b
150
+
151
+ assert_assembles_to "\x03\xC3", :add_r32_rm32,
152
+ reg0: :a, reg1: :b
153
+
154
+ assert_assembles_to "\x40\x03\xC3", :add_r32_rm32,
155
+ reg0: :a, reg1: :b, force_rex?: true
156
+
157
+ assert_disassembles_to 'add eax, ebx', :add_r32_rm32,
158
+ reg0: :a, reg1: :b, force_rex?: true
159
+
160
+ # REX.X is free
161
+ assert_assembles_to "\x42\x03\xC3", :add_r32_rm32,
162
+ reg0: :a, reg1: :b, force_rex?: true, rex_x: 0b1
163
+
164
+ # REX.X is free
165
+ assert_assembles_to "\x40\x81\xC0\x10\x00\x00\x00", :add_rm32_imm32,
166
+ reg0: :a, imm0: 0x10, force_rex?: true
167
+
168
+ assert_assembles_to "\x42\x81\xC0\x10\x00\x00\x00", :add_rm32_imm32,
169
+ reg0: :a, imm0: 0x10, force_rex?: true, rex_x: 0b1
170
+
171
+ # REX.R is free (register is encoded in ModRM.rm)
172
+ assert_assembles_to "\x44\x81\xC0\x10\x00\x00\x00", :add_rm32_imm32,
173
+ reg0: :a, imm0: 0x10, force_rex?: true, rex_r: 0b1
174
+
175
+ assert_assembles_to "\x46\x81\xC0\x10\x00\x00\x00", :add_rm32_imm32,
176
+ reg0: :a, imm0: 0x10, force_rex?: true, rex_r: 0b1, rex_x: 0b1
177
+
178
+
179
+ end
180
+
181
+ def test_byte_reg
182
+
183
+ assert_assembles_to "\x40\x02\xC3", :add_r8_rm8,
184
+ reg0: :a, reg1: :b, force_rex?: true
185
+
186
+ assert_assembles_to "\x02\xC3", :add_r8_rm8,
187
+ reg0: :a, reg1: :b, force_rex?: false
188
+
189
+ assert_assembles_to "\x40\x00\xD8", :add_rm8_r8,
190
+ reg0: :a, reg1: :b, force_rex?: true
191
+
192
+ assert_assembles_to "\x00\xD8", :add_rm8_r8,
193
+ reg0: :a, reg1: :b, force_rex?: false
194
+
195
+ %i(add_r8_rm8 add_rm8_r8).each do |inst|
196
+ assert_disassembles_to 'add al, bl', inst,
197
+ reg0: :a, reg1: :b
198
+
199
+ assert_disassembles_to 'add r11b, r12b', inst,
200
+ reg0: :r11, reg1: :r12
201
+
202
+ assert_disassembles_to 'add al, r12b', inst,
203
+ reg0: :a, reg1: :r12
204
+
205
+ assert_disassembles_to 'add al, bl', inst,
206
+ reg0: :a, reg1: :b,
207
+ force_rex?: true
208
+
209
+ assert_disassembles_to 'add ah, bl', inst,
210
+ reg0: :a, reg1: :b,
211
+ reg0_high_byte?: true
212
+
213
+ assert_disassembles_to 'add ah, al', inst,
214
+ reg0: :a, reg1: :a,
215
+ reg0_high_byte?: true
216
+
217
+ assert_disassembles_to 'add ah, bh', inst,
218
+ reg0: :a, reg1: :b,
219
+ reg0_high_byte?: true,
220
+ reg1_high_byte?: true
221
+
222
+ assert_disassembles_to 'add al, bh', inst,
223
+ reg0: :a, reg1: :b,
224
+ reg0_high_byte?: false,
225
+ reg1_high_byte?: true
226
+
227
+ assert_disassembles_to 'add sil, dil', inst,
228
+ reg0: :si, reg1: :di,
229
+ reg0_high_byte?: false,
230
+ reg1_high_byte?: false
231
+
232
+ assert_disassembles_to 'add sil, dil', inst,
233
+ reg0: :si, reg1: :di
234
+
235
+ assert_raises Evoasm::Error do
236
+ Evoasm::X64.encode :add_r8_rm8,
237
+ reg0: :si,
238
+ reg1: :b,
239
+ reg1_high_byte?: true
240
+ end
241
+ end
242
+
243
+ assert_assembles_to "\x40\xb6\x10", :mov_r8_imm8,
244
+ reg0: :si, imm0: 0x10
245
+
246
+ assert_disassembles_to 'mov sil, 0x10', :mov_r8_imm8,
247
+ reg0: :si, imm0: 0x10
248
+
249
+ end
250
+
251
+ def test_imm
252
+ assert_disassembles_to 'add rax, 0xa', :add_rm64_imm8,
253
+ reg0: :a, imm0: 0xa
254
+
255
+ assert_disassembles_to 'add qword ptr [rax], 0xa', :add_rm64_imm8,
256
+ reg_base: :a, imm0: 0xa
257
+ end
258
+
259
+ def test_vex
260
+ assert_assembles_to "\xC5\xF8\x5A\xCA", :vcvtps2pd_xmm_xmmm64,
261
+ reg0: :xmm1, reg1: :xmm2
262
+ assert_assembles_to "\xC5\xEA\x5A\xCB", :vcvtss2sd_xmm_xmm_xmmm32,
263
+ reg0: :xmm1, reg1: :xmm2, reg2: :xmm3
264
+ assert_assembles_to "\xC4\xE3\x79\x1D\xD1\x00", :vcvtps2ph_xmmm64_xmm_imm8,
265
+ reg0: :xmm1, reg1: :xmm2, imm0: 0x0
266
+ assert_assembles_to "\xC4\xC1\xFA\x2C\xFD", :vcvttss2si_r64_xmmm32,
267
+ reg0: :di, reg1: :xmm13
268
+
269
+ (0..15).each do |i|
270
+ assert_disassembles_to "vcvttss2si rdi, xmm#{i}", :vcvttss2si_r64_xmmm32,
271
+ reg0: :di, reg1: :"xmm#{i}"
272
+
273
+ assert_disassembles_to "vcvttss2si r12, xmm#{i}", :vcvttss2si_r64_xmmm32,
274
+ reg0: :r12, reg1: :"xmm#{i}"
275
+ end
276
+
277
+ assert_assembles_to "\xC5\xF5\xEC\xC2", :vpaddsb_ymm_ymm_ymmm256,
278
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, force_long_vex?: false
279
+ assert_assembles_to "\xC5\xF5\xEC\xC2", :vpaddsb_ymm_ymm_ymmm256,
280
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2
281
+ assert_assembles_to "\xC4\xE1\x75\xEC\xC2", :vpaddsb_ymm_ymm_ymmm256,
282
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, force_long_vex?: true
283
+
284
+ assert_disassembles_to 'vpaddsb ymm0, ymm1, ymm2', :vpaddsb_ymm_ymm_ymmm256,
285
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2
286
+ assert_disassembles_to 'vpaddsb ymm0, ymm1, ymm2', :vpaddsb_ymm_ymm_ymmm256,
287
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, force_long_vex?: false
288
+ assert_disassembles_to 'vpaddsb ymm0, ymm1, ymm2', :vpaddsb_ymm_ymm_ymmm256,
289
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, force_long_vex?: true
290
+
291
+ assert_disassembles_to 'vblendvpd xmm0, xmm1, xmm2, xmm3', :vblendvpd_xmm_xmm_xmmm128_xmm,
292
+ reg0: :xmm0, reg1: :xmm1, reg2: :xmm2, reg3: :xmm3
293
+ end
294
+
295
+ def test_vsib
296
+ assert_disassembles_to 'vpgatherdd xmm0, dword ptr [rax + xmm1*2], xmm2', :vpgatherdd_xmm_vm32x32_xmm,
297
+ reg0: :xmm0, reg_base: :a, reg_index: :xmm1, scale: 2, reg1: :xmm2
298
+
299
+ assert_disassembles_to 'vpgatherdd xmm0, dword ptr [rax + xmm1], xmm2', :vpgatherdd_xmm_vm32x32_xmm,
300
+ reg0: :xmm0, reg_base: :a, reg_index: :xmm1, scale: 1, reg1: :xmm2
301
+
302
+ assert_disassembles_to 'vpgatherdd xmm12, dword ptr [rax + xmm1], xmm2', :vpgatherdd_xmm_vm32x32_xmm,
303
+ reg0: :xmm12, reg_base: :a, reg_index: :xmm1, scale: 1, reg1: :xmm2
304
+
305
+ assert_disassembles_to 'vpgatherdd xmm12, dword ptr [r12 + xmm1], xmm2', :vpgatherdd_xmm_vm32x32_xmm,
306
+ reg0: :xmm12, reg_base: :r12, reg_index: :xmm1, scale: 1, reg1: :xmm2
307
+
308
+ assert_disassembles_to 'vpgatherdd xmm12, dword ptr [r12 + xmm12*8], xmm2', :vpgatherdd_xmm_vm32x32_xmm,
309
+ reg0: :xmm12, reg_base: :r12, reg_index: :xmm12, scale: 8, reg1: :xmm2
310
+
311
+ assert_disassembles_to 'vpgatherdd xmm12, dword ptr [rdi + xmm12*8], xmm2', :vpgatherdd_xmm_vm32x32_xmm,
312
+ reg0: :xmm12, reg_base: :di, reg_index: :xmm12, scale: 8, reg1: :xmm2
313
+
314
+ assert_disassembles_to 'vpgatherqq ymm12, qword ptr [rdi + ymm12*8], ymm2', :vpgatherqq_ymm_vm64y64_ymm,
315
+ reg0: :xmm12, reg_base: :di, reg_index: :xmm12, scale: 8, reg1: :xmm2
316
+
317
+ end
318
+ end
319
+ end
320
+ end