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