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.
- checksums.yaml +4 -4
- data/.gdbinit +41 -0
- data/.gitignore +1 -2
- data/.gitmodules +3 -0
- data/.rubocop.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.md +660 -0
- data/Makefile +1 -1
- data/README.md +17 -9
- data/Rakefile +39 -107
- data/bin/gdb +1 -1
- data/bin/gdb_loop +4 -0
- data/docs/FindingInstructions.md +17 -0
- data/docs/JIT.md +14 -0
- data/docs/SymbolicRegression.md +102 -0
- data/docs/Visualization.md +29 -0
- data/docs/examples/bit_insts.rb +44 -0
- data/docs/examples/jit.rb +26 -0
- data/docs/examples/loss.gif +0 -0
- data/docs/examples/program.png +0 -0
- data/docs/examples/sym_reg.rb +64 -0
- data/docs/examples/vis.rb +38 -0
- data/evoasm.gemspec +21 -15
- data/ext/evoasm_ext/Rakefile +3 -0
- data/ext/evoasm_ext/compile.rake +35 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.c +226 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.h +84 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-arch.c +52 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-arch.h +101 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-bitmap.h +158 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-buf.c +204 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-buf.h +109 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-domain.c +124 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-domain.h +279 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-error.c +65 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-error.h +108 -0
- data/ext/evoasm_ext/{evoasm-log.c → libevoasm/src/evoasm-log.c} +36 -18
- data/ext/evoasm_ext/libevoasm/src/evoasm-log.h +93 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-param.c +22 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-param.h +33 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.c +192 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.h +60 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop.c +1323 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-pop.h +107 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.c +116 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.h +60 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program.c +1827 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-program.h +167 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-rand.c +65 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-rand.h +76 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-signal.c +106 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-signal.h +58 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-util.h +112 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-x64.c +925 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm-x64.h +277 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm.c +28 -0
- data/ext/evoasm_ext/libevoasm/src/evoasm.h +35 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-enums.h +2077 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.c +191203 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.h +1713 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.c +348 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.h +93 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.c +51 -0
- data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.h +509 -0
- data/lib/evoasm.rb +28 -11
- data/lib/evoasm/buffer.rb +105 -0
- data/lib/evoasm/capstone.rb +100 -0
- data/lib/evoasm/domain.rb +116 -0
- data/lib/evoasm/error.rb +37 -16
- data/lib/evoasm/exception_error.rb +19 -0
- data/lib/evoasm/ffi_ext.rb +53 -0
- data/lib/evoasm/libevoasm.rb +286 -0
- data/lib/evoasm/libevoasm/x64_enums.rb +1967 -0
- data/lib/evoasm/parameter.rb +20 -0
- data/lib/evoasm/population.rb +145 -0
- data/lib/evoasm/population/parameters.rb +227 -0
- data/lib/evoasm/population/plotter.rb +89 -0
- data/lib/evoasm/prng.rb +64 -0
- data/lib/evoasm/program.rb +195 -12
- data/lib/evoasm/program/io.rb +144 -0
- data/lib/evoasm/test.rb +8 -0
- data/lib/evoasm/version.rb +1 -1
- data/lib/evoasm/x64.rb +115 -0
- data/lib/evoasm/x64/cpu_state.rb +95 -0
- data/lib/evoasm/x64/instruction.rb +109 -0
- data/lib/evoasm/x64/operand.rb +156 -0
- data/lib/evoasm/x64/parameters.rb +211 -0
- data/test/helpers/population_helper.rb +128 -0
- data/test/helpers/test_helper.rb +1 -0
- data/test/helpers/x64_helper.rb +24 -0
- data/test/integration/bitwise_reverse_test.rb +41 -0
- data/test/integration/gcd_test.rb +52 -0
- data/test/integration/popcnt_test.rb +46 -0
- data/test/integration/sym_reg_test.rb +68 -0
- data/test/unit/evoasm/buffer_test.rb +48 -0
- data/test/unit/evoasm/capstone_test.rb +18 -0
- data/test/unit/evoasm/domain_test.rb +55 -0
- data/test/unit/evoasm/population/parameters_test.rb +106 -0
- data/test/unit/evoasm/population_test.rb +96 -0
- data/test/unit/evoasm/prng_test.rb +47 -0
- data/test/unit/evoasm/x64/cpu_state_test.rb +73 -0
- data/test/unit/evoasm/x64/encoding_test.rb +320 -0
- data/test/unit/evoasm/x64/instruction_access_test.rb +177 -0
- data/test/unit/evoasm/x64/instruction_encoding_test.rb +780 -0
- data/test/unit/evoasm/x64/instruction_test.rb +62 -0
- data/test/unit/evoasm/x64/parameters_test.rb +65 -0
- data/test/unit/evoasm/x64_test.rb +52 -0
- metadata +195 -89
- data/Gemfile.rake +0 -8
- data/Gemfile.rake.lock +0 -51
- data/LICENSE.txt +0 -373
- data/data/tables/README.md +0 -19
- data/data/tables/x64.csv +0 -1684
- data/data/templates/evoasm-x64.c.erb +0 -319
- data/data/templates/evoasm-x64.h.erb +0 -126
- data/examples/abs.yml +0 -20
- data/examples/popcnt.yml +0 -17
- data/examples/sym_reg.yml +0 -26
- data/exe/evoasm-search +0 -13
- data/ext/evoasm_ext/evoasm-alloc.c +0 -145
- data/ext/evoasm_ext/evoasm-alloc.h +0 -59
- data/ext/evoasm_ext/evoasm-arch.c +0 -44
- data/ext/evoasm_ext/evoasm-arch.h +0 -161
- data/ext/evoasm_ext/evoasm-bitmap.h +0 -114
- data/ext/evoasm_ext/evoasm-buf.c +0 -130
- data/ext/evoasm_ext/evoasm-buf.h +0 -47
- data/ext/evoasm_ext/evoasm-error.c +0 -31
- data/ext/evoasm_ext/evoasm-error.h +0 -75
- data/ext/evoasm_ext/evoasm-free-list.c.tmpl +0 -121
- data/ext/evoasm_ext/evoasm-free-list.h.tmpl +0 -86
- data/ext/evoasm_ext/evoasm-log.h +0 -69
- data/ext/evoasm_ext/evoasm-misc.c +0 -23
- data/ext/evoasm_ext/evoasm-misc.h +0 -282
- data/ext/evoasm_ext/evoasm-param.h +0 -37
- data/ext/evoasm_ext/evoasm-search.c +0 -2145
- data/ext/evoasm_ext/evoasm-search.h +0 -214
- data/ext/evoasm_ext/evoasm-util.h +0 -40
- data/ext/evoasm_ext/evoasm-x64.c +0 -275624
- data/ext/evoasm_ext/evoasm-x64.h +0 -5436
- data/ext/evoasm_ext/evoasm.c +0 -7
- data/ext/evoasm_ext/evoasm.h +0 -23
- data/ext/evoasm_ext/evoasm_ext.c +0 -1757
- data/ext/evoasm_ext/extconf.rb +0 -31
- data/lib/evoasm/cli.rb +0 -6
- data/lib/evoasm/cli/search.rb +0 -127
- data/lib/evoasm/core_ext.rb +0 -1
- data/lib/evoasm/core_ext/array.rb +0 -9
- data/lib/evoasm/core_ext/integer.rb +0 -10
- data/lib/evoasm/core_ext/kwstruct.rb +0 -13
- data/lib/evoasm/core_ext/range.rb +0 -5
- data/lib/evoasm/examples.rb +0 -27
- data/lib/evoasm/gen.rb +0 -8
- data/lib/evoasm/gen/enum.rb +0 -169
- data/lib/evoasm/gen/name_util.rb +0 -80
- data/lib/evoasm/gen/state.rb +0 -176
- data/lib/evoasm/gen/state_dsl.rb +0 -152
- data/lib/evoasm/gen/strio.rb +0 -27
- data/lib/evoasm/gen/translator.rb +0 -1102
- data/lib/evoasm/gen/version.rb +0 -5
- data/lib/evoasm/gen/x64.rb +0 -237
- data/lib/evoasm/gen/x64/funcs.rb +0 -495
- data/lib/evoasm/gen/x64/inst.rb +0 -781
- data/lib/evoasm/search.rb +0 -40
- data/lib/evoasm/tasks/gen_task.rb +0 -86
- data/lib/evoasm/tasks/template_task.rb +0 -52
- data/test/test_helper.rb +0 -1
- data/test/x64/test_helper.rb +0 -19
- 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
|