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,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