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
data/lib/evoasm/gen/state.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Evoasm::Gen
|
4
|
-
State = Struct.new(:children, :actions, :ret, :_local_params) do
|
5
|
-
attr_accessor :id, :comment, :parents
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
self.children = []
|
9
|
-
self.parents = []
|
10
|
-
self.actions = []
|
11
|
-
self._local_params = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def local_params
|
15
|
-
child_local_params = children.map do |child, _, _|
|
16
|
-
child.local_params
|
17
|
-
end
|
18
|
-
all_local_params = (_local_params + child_local_params)
|
19
|
-
all_local_params.flatten!
|
20
|
-
all_local_params.uniq!
|
21
|
-
|
22
|
-
all_local_params
|
23
|
-
end
|
24
|
-
|
25
|
-
def add_local_param(param)
|
26
|
-
if param.to_s[0] != '_'
|
27
|
-
fail ArgumentError, 'params must start with underscore'
|
28
|
-
end
|
29
|
-
|
30
|
-
_local_params << param unless _local_params.include? param
|
31
|
-
end
|
32
|
-
|
33
|
-
protected def add_parent(parent)
|
34
|
-
parents << parent unless parents.include? parent
|
35
|
-
end
|
36
|
-
|
37
|
-
def add_child(child, cond = nil, priority)
|
38
|
-
child.add_parent self
|
39
|
-
children << [child, cond, priority]
|
40
|
-
end
|
41
|
-
|
42
|
-
%i(sets asserts calls writes debugs).each do |name|
|
43
|
-
action_name = name.to_s[0..-2].to_sym
|
44
|
-
define_method name do
|
45
|
-
actions.select { |action, _| action == action_name }
|
46
|
-
.map { |_, args| args }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
private def roots
|
51
|
-
return [self] if parents.empty?
|
52
|
-
parents.flat_map(&:roots)
|
53
|
-
end
|
54
|
-
|
55
|
-
def root
|
56
|
-
roots = roots()
|
57
|
-
fail 'multiple roots' if roots.size > 1
|
58
|
-
roots.first
|
59
|
-
end
|
60
|
-
|
61
|
-
def empty?
|
62
|
-
actions.empty?
|
63
|
-
end
|
64
|
-
|
65
|
-
def terminal?
|
66
|
-
children.empty?
|
67
|
-
end
|
68
|
-
|
69
|
-
def ret?
|
70
|
-
ret != nil
|
71
|
-
end
|
72
|
-
|
73
|
-
def to_gv
|
74
|
-
require 'gv'
|
75
|
-
|
76
|
-
graph = GV::Graph.open 'ast'
|
77
|
-
graph[:ranksep] = 1.5
|
78
|
-
graph[:statesep] = 0.8
|
79
|
-
__to_gv__ graph
|
80
|
-
graph
|
81
|
-
end
|
82
|
-
|
83
|
-
def __to_gv__(graph, gv_parent = nil, cond = nil, attrs = {}, index = nil, seen = {})
|
84
|
-
if seen.key?(self)
|
85
|
-
# return
|
86
|
-
else
|
87
|
-
seen[self] = true
|
88
|
-
end
|
89
|
-
|
90
|
-
edge_label = ''
|
91
|
-
state_label = ''
|
92
|
-
|
93
|
-
if cond
|
94
|
-
if cond.first == :else
|
95
|
-
edge_label << "<b> else</b><br></br>\n"
|
96
|
-
else
|
97
|
-
edge_label << "<b> if</b> #{expr_to_s cond}<br></br>\n"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
if attrs
|
102
|
-
attrs.each do |name, value|
|
103
|
-
edge_label << "<b> #{name}</b>: #{value}<br></br>\n"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
actions.each do |name, args|
|
108
|
-
state_label << send(:"label_#{name}", *args)
|
109
|
-
end
|
110
|
-
|
111
|
-
state_label << "<i>#{comment}</i>\n" if comment
|
112
|
-
|
113
|
-
gv_state = graph.node object_id.to_s,
|
114
|
-
shape: (self.ret? ? :house : (state_label.empty? ? :point : :box)),
|
115
|
-
label: graph.html(state_label)
|
116
|
-
|
117
|
-
children.each_with_index do |(child, cond, attrs), index|
|
118
|
-
child.__to_gv__(graph, gv_state, cond, attrs, index, seen)
|
119
|
-
end
|
120
|
-
|
121
|
-
if gv_parent
|
122
|
-
graph.edge gv_parent.name + '.' + gv_state.name + index.to_s,
|
123
|
-
gv_parent, gv_state,
|
124
|
-
label: graph.html(edge_label)
|
125
|
-
end
|
126
|
-
|
127
|
-
graph
|
128
|
-
end
|
129
|
-
|
130
|
-
private
|
131
|
-
|
132
|
-
def label_set(name, value, _options = {})
|
133
|
-
"<b>set</b> #{name} := #{expr_to_s value}<br></br>"
|
134
|
-
end
|
135
|
-
|
136
|
-
def label_assert(cond)
|
137
|
-
"<b>assert</b> #{expr_to_s cond}<br></br>"
|
138
|
-
end
|
139
|
-
|
140
|
-
def label_call(name)
|
141
|
-
"<b>call</b> #{name}<br></br>"
|
142
|
-
end
|
143
|
-
|
144
|
-
def label_debug(_format, *_args)
|
145
|
-
''
|
146
|
-
end
|
147
|
-
|
148
|
-
def label_write(value, size)
|
149
|
-
label =
|
150
|
-
if value.is_a?(Integer) && size.is_a?(Integer)
|
151
|
-
if size == 8
|
152
|
-
'x%x' % value
|
153
|
-
else
|
154
|
-
"b%0#{size}b" % value
|
155
|
-
end
|
156
|
-
elsif size.is_a? Array
|
157
|
-
Array(value).zip(Array(size)).map do |v, s|
|
158
|
-
"#{expr_to_s v} [#{expr_to_s s}]"
|
159
|
-
end.join ', '
|
160
|
-
else
|
161
|
-
"#{expr_to_s value} [#{expr_to_s size}]"
|
162
|
-
end
|
163
|
-
"<b>output</b> #{label}<br></br>"
|
164
|
-
end
|
165
|
-
|
166
|
-
def expr_to_s(pred)
|
167
|
-
case pred
|
168
|
-
when Array
|
169
|
-
pred, *args = *pred
|
170
|
-
"#{pred}(#{args.map { |a| expr_to_s(a) }.join(', ')})"
|
171
|
-
else
|
172
|
-
pred
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
data/lib/evoasm/gen/state_dsl.rb
DELETED
@@ -1,152 +0,0 @@
|
|
1
|
-
require 'evoasm/gen/state'
|
2
|
-
|
3
|
-
module Evoasm::Gen
|
4
|
-
module StateDSL
|
5
|
-
LOWEST_PRIORITY = 999
|
6
|
-
|
7
|
-
def self.included(base)
|
8
|
-
base.send :extend, ClassMethods
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def state(name)
|
13
|
-
f = instance_method(name)
|
14
|
-
var_name = :"@#{name}"
|
15
|
-
|
16
|
-
define_method(name) do
|
17
|
-
return instance_variable_get var_name if instance_variable_defined? var_name
|
18
|
-
instance_variable_set var_name, f.bind(self).call
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class DSLState
|
24
|
-
include StateDSL
|
25
|
-
|
26
|
-
def initialize(state)
|
27
|
-
@__state__ = state
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def comment(comment = nil)
|
32
|
-
if comment
|
33
|
-
@__state__.comment = comment
|
34
|
-
else
|
35
|
-
@__state__.comment
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def exec(name, args)
|
40
|
-
@__state__.actions << [name, args]
|
41
|
-
end
|
42
|
-
|
43
|
-
def set(param, value, options = {})
|
44
|
-
fail ArgumentError, 'nil not allowed' if value.nil?
|
45
|
-
exec :set, [param.to_sym, value, options]
|
46
|
-
@__state__.add_local_param param
|
47
|
-
end
|
48
|
-
|
49
|
-
def write(value = nil, size = nil)
|
50
|
-
if Array === size && Array === value
|
51
|
-
fail ArgumentError, 'values and sizes must have same length' unless value.size == size.size
|
52
|
-
end
|
53
|
-
exec :write, [value, size]
|
54
|
-
end
|
55
|
-
|
56
|
-
def unordered_writes(param_name, writes)
|
57
|
-
exec :unordered_writes, [param_name, writes]
|
58
|
-
end
|
59
|
-
|
60
|
-
def call(func)
|
61
|
-
exec :call, [func]
|
62
|
-
end
|
63
|
-
|
64
|
-
def access(op, modes)
|
65
|
-
exec :access, [op, modes]
|
66
|
-
end
|
67
|
-
|
68
|
-
def recover_with(param, range = nil, **opts)
|
69
|
-
@__state__.recovery << [param, range, opts]
|
70
|
-
end
|
71
|
-
|
72
|
-
def log(level, msg, *args)
|
73
|
-
exec :log, [level, msg, *args]
|
74
|
-
end
|
75
|
-
|
76
|
-
def assert(*args)
|
77
|
-
exec :assert, args
|
78
|
-
end
|
79
|
-
|
80
|
-
def calls?(name)
|
81
|
-
@__state__.calls.include? name
|
82
|
-
end
|
83
|
-
|
84
|
-
def ret
|
85
|
-
@__state__.ret = true
|
86
|
-
end
|
87
|
-
|
88
|
-
def error(code = nil, msg = nil, reg: nil, param: nil)
|
89
|
-
exec :error, [code, msg, reg, param]
|
90
|
-
ret
|
91
|
-
end
|
92
|
-
|
93
|
-
def to(child = nil, **attrs, &block)
|
94
|
-
if child.nil?
|
95
|
-
child = State.new
|
96
|
-
instance_eval_with_state child, &block
|
97
|
-
end
|
98
|
-
|
99
|
-
@__state__.add_child child, nil, default_attrs(attrs)
|
100
|
-
child
|
101
|
-
end
|
102
|
-
|
103
|
-
def lowest_priority
|
104
|
-
@__state__.children.map { |_, _, attrs| attrs[:priority] }.max || 0
|
105
|
-
end
|
106
|
-
|
107
|
-
def default_attrs(attrs)
|
108
|
-
{ priority: lowest_priority + 1 }.merge attrs
|
109
|
-
end
|
110
|
-
|
111
|
-
def else_to(state = nil, &block)
|
112
|
-
to_if(:else, state, priority: LOWEST_PRIORITY, &block)
|
113
|
-
end
|
114
|
-
|
115
|
-
def to_if(*args, **attrs, &block)
|
116
|
-
if block
|
117
|
-
child = State.new
|
118
|
-
instance_eval_with_state child, &block
|
119
|
-
|
120
|
-
args.compact!
|
121
|
-
else
|
122
|
-
child = args.pop
|
123
|
-
end
|
124
|
-
|
125
|
-
@__state__.add_child child, args, default_attrs(attrs)
|
126
|
-
child
|
127
|
-
end
|
128
|
-
|
129
|
-
def self_state
|
130
|
-
@__state__
|
131
|
-
end
|
132
|
-
|
133
|
-
def state(*args, &block)
|
134
|
-
if args.size == 1 && State === args.first
|
135
|
-
instance_eval_with_state(args.first, &block)
|
136
|
-
else
|
137
|
-
State.new(*args).tap do |s|
|
138
|
-
instance_eval_with_state(s, &block)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def instance_eval_with_state(state, &block)
|
144
|
-
prev_state = @__state__
|
145
|
-
@__state__ = state
|
146
|
-
result = instance_eval(&block) if block
|
147
|
-
@__state__ = prev_state
|
148
|
-
|
149
|
-
result
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
data/lib/evoasm/gen/strio.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Evoasm
|
2
|
-
module Gen
|
3
|
-
class StrIO < ::StringIO
|
4
|
-
def indent(indent = nil)
|
5
|
-
@indent ||= 0
|
6
|
-
|
7
|
-
prev_indent = @indent
|
8
|
-
@indent = indent || @indent + 1
|
9
|
-
yield
|
10
|
-
@indent = prev_indent
|
11
|
-
end
|
12
|
-
|
13
|
-
def indent_str
|
14
|
-
' ' * @indent
|
15
|
-
end
|
16
|
-
|
17
|
-
def puts(line = nil, eol: '')
|
18
|
-
if line
|
19
|
-
write indent_str if @indent
|
20
|
-
super("#{line}#{eol}")
|
21
|
-
else
|
22
|
-
super()
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,1102 +0,0 @@
|
|
1
|
-
require 'erubis'
|
2
|
-
require 'evoasm/gen/strio'
|
3
|
-
require 'evoasm/gen/enum'
|
4
|
-
require 'evoasm/gen/name_util'
|
5
|
-
require 'evoasm/gen/x64'
|
6
|
-
|
7
|
-
module Evoasm
|
8
|
-
module Gen
|
9
|
-
class BaseTranslator
|
10
|
-
include NameUtil
|
11
|
-
|
12
|
-
PARAMS_ARG_HELPERS = %i(address_size operand_size disp_size)
|
13
|
-
NO_ARCH_HELPERS = %i(log2)
|
14
|
-
|
15
|
-
def acc_c_type
|
16
|
-
name_to_c :bitmap128
|
17
|
-
end
|
18
|
-
|
19
|
-
def arch_c_type
|
20
|
-
name_to_c arch
|
21
|
-
end
|
22
|
-
|
23
|
-
def param_val_c_type
|
24
|
-
name_to_c 'arch_param_val'
|
25
|
-
end
|
26
|
-
|
27
|
-
def bitmap_c_type
|
28
|
-
name_to_c 'bitmap'
|
29
|
-
end
|
30
|
-
|
31
|
-
def local_param?(name)
|
32
|
-
name.to_s[0] == '_'
|
33
|
-
end
|
34
|
-
|
35
|
-
def arch_var_name(indep_arch = false)
|
36
|
-
"#{indep_arch ? '((evoasm_arch *)' : ''}#{arch}#{indep_arch ? ')' : ''}"
|
37
|
-
end
|
38
|
-
|
39
|
-
def call_to_c(func, args, prefix = nil, eol: false)
|
40
|
-
func_name = func.to_s.gsub('?', '_p')
|
41
|
-
|
42
|
-
if prefix
|
43
|
-
args.unshift arch_var_name(Array(prefix).first != arch)
|
44
|
-
end
|
45
|
-
|
46
|
-
"#{name_to_c func_name, prefix}(#{args.join ','})" + (eol ? ';' : '')
|
47
|
-
end
|
48
|
-
|
49
|
-
def params_c_args
|
50
|
-
"#{param_val_c_type} *param_vals, "\
|
51
|
-
"#{bitmap_c_type} *set_params"
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
def params_args
|
56
|
-
%w(param_vals set_params)
|
57
|
-
end
|
58
|
-
|
59
|
-
def param_to_c(name)
|
60
|
-
register_param name.to_sym
|
61
|
-
param_name_to_c name
|
62
|
-
end
|
63
|
-
|
64
|
-
def register_param(name)
|
65
|
-
return if local_param? name
|
66
|
-
main_translator.register_param name
|
67
|
-
registered_params << name
|
68
|
-
end
|
69
|
-
|
70
|
-
def helper_to_c(expr)
|
71
|
-
if expr.first.is_a?(Array)
|
72
|
-
fail expr.inspect unless expr.size == 1
|
73
|
-
expr = expr.first
|
74
|
-
end
|
75
|
-
|
76
|
-
name, *args = simplify_helper expr
|
77
|
-
case name
|
78
|
-
when :eq, :gt, :lt, :gtq, :ltq
|
79
|
-
"(#{expr_to_c args[0]} #{cmp_helper_to_c name} #{expr_to_c args[1]})"
|
80
|
-
when :if
|
81
|
-
"(#{expr_to_c args[0]} ? (#{expr_to_c args[1]}) : #{expr_to_c args[2]})"
|
82
|
-
when :neg
|
83
|
-
"~(#{expr_to_c args[0]})"
|
84
|
-
when :shl
|
85
|
-
infix_op_to_c '<<', args
|
86
|
-
when :mod
|
87
|
-
infix_op_to_c '%', args
|
88
|
-
when :div
|
89
|
-
infix_op_to_c '/', args
|
90
|
-
when :add
|
91
|
-
infix_op_to_c '+', args
|
92
|
-
when :sub
|
93
|
-
infix_op_to_c '-', args
|
94
|
-
when :set?
|
95
|
-
set_p_to_c(*args)
|
96
|
-
when :not
|
97
|
-
"!(#{expr_to_c args[0]})"
|
98
|
-
when :max, :min
|
99
|
-
"#{name.to_s.upcase}(#{args.map { |a| expr_to_c a }.join(', ')})"
|
100
|
-
when :and
|
101
|
-
infix_op_to_c '&&', args
|
102
|
-
when :or
|
103
|
-
infix_op_to_c '||', args
|
104
|
-
when :in?
|
105
|
-
args[1..-1].map { |a| "#{expr_to_c args[0]} == #{expr_to_c a}" }
|
106
|
-
.join(" ||\n#{io.indent_str + ' '}")
|
107
|
-
else
|
108
|
-
if !name.is_a?(Symbol)
|
109
|
-
fail unless args.empty?
|
110
|
-
expr_to_c name
|
111
|
-
else
|
112
|
-
call_args = args.map { |a| expr_to_c(a) }
|
113
|
-
call_args.concat params_args if PARAMS_ARG_HELPERS.include? name
|
114
|
-
if name == :reg_code
|
115
|
-
call_args[0] = "(evoasm_#{arch}_reg_id) #{call_args[0]}"
|
116
|
-
end
|
117
|
-
helper_call_to_c name, call_args
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def expr_to_c(expr, const_prefix: nil)
|
123
|
-
case expr
|
124
|
-
when Array
|
125
|
-
helper_to_c expr
|
126
|
-
when TrueClass
|
127
|
-
'true'
|
128
|
-
when FalseClass
|
129
|
-
'false'
|
130
|
-
when Numeric
|
131
|
-
expr
|
132
|
-
when Symbol, String
|
133
|
-
s = expr.to_s
|
134
|
-
if s != s.upcase
|
135
|
-
get_to_c s
|
136
|
-
else
|
137
|
-
if X64::REGISTER_NAMES.include?(s.to_sym)
|
138
|
-
const_prefix = [arch, 'reg']
|
139
|
-
elsif s =~ /^INT\d+_(MAX|MIN)$/
|
140
|
-
const_prefix = nil
|
141
|
-
end
|
142
|
-
|
143
|
-
name_to_c s, const_prefix, const: true
|
144
|
-
end
|
145
|
-
else
|
146
|
-
fail "invalid expression #{expr.inspect}"
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def func_prototype_to_c(name, func_params = [], static: true)
|
151
|
-
func_name = name_to_c name, arch
|
152
|
-
|
153
|
-
func_params_c =
|
154
|
-
if func_params.empty?
|
155
|
-
''
|
156
|
-
else
|
157
|
-
func_params.map do |param_name, type|
|
158
|
-
"#{type} #{param_name}"
|
159
|
-
end.join(', ').prepend ', '
|
160
|
-
end
|
161
|
-
"#{static ? 'static ' : ''}evoasm_success\n#{func_name}(#{arch_c_type} *#{arch_var_name},"\
|
162
|
-
" #{params_c_args}#{func_params_c})"
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
class FuncTranslator < BaseTranslator
|
167
|
-
INST_STATE_ID_MIN = 32
|
168
|
-
INST_STATE_ID_MAX = 2000
|
169
|
-
|
170
|
-
attr_reader :inst, :registered_params, :root_state
|
171
|
-
attr_reader :main_translator, :id_map
|
172
|
-
attr_reader :arch, :io, :param_domains
|
173
|
-
|
174
|
-
def initialize(arch, main_translator)
|
175
|
-
@arch = arch
|
176
|
-
@main_translator = main_translator
|
177
|
-
@id = INST_STATE_ID_MAX
|
178
|
-
@id_map = Hash.new { |h, k| h[k] = (@id += 1) }
|
179
|
-
@registered_params = Set.new
|
180
|
-
@param_domains = {}
|
181
|
-
end
|
182
|
-
|
183
|
-
def with_io(io)
|
184
|
-
@io = io
|
185
|
-
yield
|
186
|
-
@io = nil
|
187
|
-
end
|
188
|
-
|
189
|
-
def pref_func_name(id)
|
190
|
-
"prefs_#{id}"
|
191
|
-
end
|
192
|
-
|
193
|
-
def inst_id_c_type
|
194
|
-
name_to_c :inst_id
|
195
|
-
end
|
196
|
-
|
197
|
-
def called_func_name(func, id)
|
198
|
-
attrs = func.each_pair.map { |k, v| [k, v].join('_') }.flatten.join('__')
|
199
|
-
"#{func.class.name.split('::').last.downcase}_#{attrs}_#{id}"
|
200
|
-
end
|
201
|
-
|
202
|
-
def emit_func(name, root_state, func_params = [], local_acc: true, static: true)
|
203
|
-
io.puts func_prototype_to_c(name, func_params, static: static), eol: ' {'
|
204
|
-
|
205
|
-
io.indent do
|
206
|
-
emit_func_prolog root_state, local_acc
|
207
|
-
emit_state root_state
|
208
|
-
emit_func_epilog local_acc
|
209
|
-
end
|
210
|
-
|
211
|
-
|
212
|
-
io.puts '}'
|
213
|
-
io.puts
|
214
|
-
end
|
215
|
-
|
216
|
-
def emit_acc_ary_copy(back_copy = false)
|
217
|
-
var_name = 'acc'
|
218
|
-
src = "#{arch_var_name arch_indep: true}->#{var_name}"
|
219
|
-
dst = var_name
|
220
|
-
|
221
|
-
dst, src = src, dst if back_copy
|
222
|
-
io.puts "#{dst} = #{src};"
|
223
|
-
end
|
224
|
-
|
225
|
-
def emit_func_prolog(root_state, acc)
|
226
|
-
local_params = root_state.local_params
|
227
|
-
unless local_params.empty?
|
228
|
-
io.puts "#{param_val_c_type} #{local_params.join ', '};"
|
229
|
-
local_params.each do |param|
|
230
|
-
io.puts "(void) #{param};"
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
io.puts 'bool retval = true;'
|
235
|
-
|
236
|
-
if acc
|
237
|
-
io.puts "#{acc_c_type} acc;"
|
238
|
-
emit_acc_ary_copy
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def error_data_field_to_c(field_name)
|
243
|
-
"#{arch_var_name arch_indep: true}->error_data.#{field_name}"
|
244
|
-
end
|
245
|
-
|
246
|
-
def emit_error(state, code, msg, reg = nil, param = nil)
|
247
|
-
reg_c_val =
|
248
|
-
if reg
|
249
|
-
reg_name_to_c reg
|
250
|
-
else
|
251
|
-
"(uint8_t) -1"
|
252
|
-
end
|
253
|
-
param_c_val =
|
254
|
-
if param
|
255
|
-
param_to_c param
|
256
|
-
else
|
257
|
-
"(uint8_t) -1"
|
258
|
-
end
|
259
|
-
|
260
|
-
io.write <<-EOL
|
261
|
-
evoasm_arch_error_data error_data = {
|
262
|
-
.reg = #{reg_c_val},
|
263
|
-
.param = #{param_c_val},
|
264
|
-
.arch = #{arch_var_name arch_indep: true},
|
265
|
-
};
|
266
|
-
EOL
|
267
|
-
|
268
|
-
io.puts %Q{evoasm_set_error(EVOASM_ERROR_TYPE_ARCH, #{error_code_to_c code}, &error_data, "#{msg}");}
|
269
|
-
io.puts 'retval = false;'
|
270
|
-
end
|
271
|
-
|
272
|
-
def emit_func_epilog(acc)
|
273
|
-
io.indent 0 do
|
274
|
-
io.puts "exit:"
|
275
|
-
end
|
276
|
-
emit_acc_ary_copy true if acc
|
277
|
-
io.puts "return retval;"
|
278
|
-
|
279
|
-
io.indent 0 do
|
280
|
-
io.puts "error:"
|
281
|
-
end
|
282
|
-
|
283
|
-
io.puts 'retval = false;'
|
284
|
-
io.puts 'goto exit;'
|
285
|
-
end
|
286
|
-
|
287
|
-
def emit_state(state)
|
288
|
-
fail if state.nil?
|
289
|
-
|
290
|
-
unemitted_states = []
|
291
|
-
|
292
|
-
fail if state.ret? && !state.terminal?
|
293
|
-
|
294
|
-
emit_body state, unemitted_states
|
295
|
-
|
296
|
-
unemitted_states.each do |unemitted_state|
|
297
|
-
emit_state unemitted_state
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def emit_body(state, unemitted_states, inlined = false)
|
302
|
-
fail state.actions.inspect unless deterministic?(state)
|
303
|
-
io.puts '/* begin inlined */' if inlined
|
304
|
-
|
305
|
-
emit_label state unless inlined
|
306
|
-
|
307
|
-
actions = state.actions.dup.reverse
|
308
|
-
emit_actions state, actions, unemitted_states
|
309
|
-
|
310
|
-
emit_ret state if state.ret?
|
311
|
-
|
312
|
-
emit_transitions(state, unemitted_states)
|
313
|
-
|
314
|
-
io.puts '/* end inlined */' if inlined
|
315
|
-
end
|
316
|
-
|
317
|
-
def emit_comment(state)
|
318
|
-
io.puts "/* #{state.comment} (#{state.object_id}) */" if state.comment
|
319
|
-
end
|
320
|
-
|
321
|
-
def emit_label(state)
|
322
|
-
io.indent 0 do
|
323
|
-
io.puts "#{state_label state}:;"
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def has_else?(state)
|
328
|
-
state.children.any? { |_, cond| cond == [:else] }
|
329
|
-
end
|
330
|
-
|
331
|
-
def emit_ret(state)
|
332
|
-
io.puts "goto exit;"
|
333
|
-
end
|
334
|
-
|
335
|
-
def state_label(state, id = nil)
|
336
|
-
"L#{id || id_map[state]}"
|
337
|
-
end
|
338
|
-
|
339
|
-
def emit_call(state, func)
|
340
|
-
id = main_translator.request_func_call func, self
|
341
|
-
|
342
|
-
func_call = call_to_c called_func_name(func, id),
|
343
|
-
[*params_args, inst_name_to_c(inst), '&acc'],
|
344
|
-
arch_prefix
|
345
|
-
|
346
|
-
io.puts "if(!#{func_call}){goto error;}"
|
347
|
-
end
|
348
|
-
|
349
|
-
def emit_goto_transition(child)
|
350
|
-
io.puts "goto #{state_label child};"
|
351
|
-
end
|
352
|
-
|
353
|
-
def emit_transitions(state, unemitted_states, &block)
|
354
|
-
state
|
355
|
-
.children
|
356
|
-
.sort_by { |_, _, attrs| attrs[:priority] }
|
357
|
-
.each do |child, expr|
|
358
|
-
emit_cond expr do
|
359
|
-
if inlineable?(child)
|
360
|
-
block[] if block
|
361
|
-
emit_body(child, unemitted_states, true)
|
362
|
-
true
|
363
|
-
else
|
364
|
-
unemitted_states << child unless id_map.key?(child)
|
365
|
-
block[] if block
|
366
|
-
emit_goto_transition(child)
|
367
|
-
false
|
368
|
-
end
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
fail 'missing else branch' if can_get_stuck?(state)
|
373
|
-
end
|
374
|
-
|
375
|
-
def can_get_stuck?(state)
|
376
|
-
return false if state.ret?
|
377
|
-
return false if has_else? state
|
378
|
-
|
379
|
-
fail state.actions.inspect if state.children.empty?
|
380
|
-
|
381
|
-
return false if state.children.any? do |_child, cond|
|
382
|
-
cond.nil? || cond == [true]
|
383
|
-
end
|
384
|
-
|
385
|
-
true
|
386
|
-
end
|
387
|
-
|
388
|
-
def helper_call_to_c(name, args)
|
389
|
-
prefix =
|
390
|
-
if NO_ARCH_HELPERS.include?(name)
|
391
|
-
nil
|
392
|
-
else
|
393
|
-
arch_prefix
|
394
|
-
end
|
395
|
-
|
396
|
-
call_to_c name, args, prefix
|
397
|
-
end
|
398
|
-
|
399
|
-
def simplify_helper(helper)
|
400
|
-
simplified_helper = simplify_helper_ helper
|
401
|
-
return simplified_helper if simplified_helper == helper
|
402
|
-
simplify_helper simplified_helper
|
403
|
-
end
|
404
|
-
|
405
|
-
def simplify_helper_(helper)
|
406
|
-
name, *args = helper
|
407
|
-
case name
|
408
|
-
when :neq
|
409
|
-
[:not, [:eq, *args]]
|
410
|
-
when :false?
|
411
|
-
[:eq, *args, 0]
|
412
|
-
when :true?
|
413
|
-
[:not, [:false?, *args]]
|
414
|
-
when :unset?
|
415
|
-
[:not, [:set?, args[0]]]
|
416
|
-
when :in?
|
417
|
-
[:or, *args[1..-1].map { |arg| [:eq, args.first, arg] }]
|
418
|
-
when :not_in?
|
419
|
-
[:not, [:in?, *args]]
|
420
|
-
else
|
421
|
-
helper
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
def emit_cond(cond, else_if: false, &block)
|
426
|
-
cond_str =
|
427
|
-
if cond.nil? || cond == true
|
428
|
-
''
|
429
|
-
elsif cond[0] == :else
|
430
|
-
'else '
|
431
|
-
else
|
432
|
-
"#{else_if ? 'else ' : ''}if(#{expr_to_c cond})"
|
433
|
-
end
|
434
|
-
|
435
|
-
emit_c_block cond_str, &block
|
436
|
-
end
|
437
|
-
|
438
|
-
def emit_log(_state, level, msg, *exprs)
|
439
|
-
expr_part =
|
440
|
-
if !exprs.empty?
|
441
|
-
", #{exprs.map { |expr| "(#{param_val_c_type}) #{expr_to_c expr}" }.join(', ')}"
|
442
|
-
else
|
443
|
-
''
|
444
|
-
end
|
445
|
-
msg = msg.gsub('%', '%" EVOASM_PARAM_VAL_FORMAT "')
|
446
|
-
io.puts %[evoasm_#{level}("#{msg}" #{expr_part});]
|
447
|
-
end
|
448
|
-
|
449
|
-
def emit_assert(_state, *expr)
|
450
|
-
io.puts "assert(#{expr_to_c expr});"
|
451
|
-
end
|
452
|
-
|
453
|
-
def set_p_to_c(key, eol: false)
|
454
|
-
call_to_c 'bitmap_get',
|
455
|
-
["(#{bitmap_c_type} *) set_params", param_to_c(key)],
|
456
|
-
eol: eol
|
457
|
-
end
|
458
|
-
|
459
|
-
def get_to_c(key, eol: false)
|
460
|
-
if local_param? key
|
461
|
-
key.to_s
|
462
|
-
else
|
463
|
-
"param_vals[#{param_to_c(key)}]" + (eol ? ';' : '')
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
def emit_set(_state, key, value, c_value: false)
|
468
|
-
fail "setting non-local param '#{key}' is not allowed" unless local_param? key
|
469
|
-
|
470
|
-
c_value =
|
471
|
-
if c_value
|
472
|
-
value
|
473
|
-
else
|
474
|
-
expr_to_c value
|
475
|
-
end
|
476
|
-
|
477
|
-
io.puts "#{key} = #{c_value};"
|
478
|
-
end
|
479
|
-
|
480
|
-
def merge_params(params)
|
481
|
-
params.each do |param|
|
482
|
-
register_param param
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
def cmp_helper_to_c(name)
|
487
|
-
case name
|
488
|
-
when :eq then '=='
|
489
|
-
when :gt then '>'
|
490
|
-
when :lt then '<'
|
491
|
-
when :gtq then '>='
|
492
|
-
when :ltq then '<='
|
493
|
-
else
|
494
|
-
fail
|
495
|
-
end
|
496
|
-
end
|
497
|
-
|
498
|
-
def infix_op_to_c(op, args)
|
499
|
-
"(#{args.map { |a| expr_to_c a }.join(" #{op} ")})"
|
500
|
-
end
|
501
|
-
|
502
|
-
def emit_actions(state, actions, _unemitted_states)
|
503
|
-
io.puts '/* actions */'
|
504
|
-
until actions.empty?
|
505
|
-
name, args = actions.last
|
506
|
-
actions.pop
|
507
|
-
send :"emit_#{name}", state, *args
|
508
|
-
end
|
509
|
-
end
|
510
|
-
|
511
|
-
def deterministic?(state)
|
512
|
-
n_children = state.children.size
|
513
|
-
|
514
|
-
n_children <= 1 ||
|
515
|
-
(n_children == 2 && has_else?(state))
|
516
|
-
end
|
517
|
-
|
518
|
-
def inlineable?(state)
|
519
|
-
state.parents.size == 1 &&
|
520
|
-
deterministic?(state.parents.first)
|
521
|
-
end
|
522
|
-
|
523
|
-
def emit_c_block(code = nil, &block)
|
524
|
-
io.puts "#{code}{"
|
525
|
-
io.indent do
|
526
|
-
block[]
|
527
|
-
end
|
528
|
-
io.puts '}'
|
529
|
-
end
|
530
|
-
|
531
|
-
def emit_unordered_writes(state, param_name, writes)
|
532
|
-
if writes.size > 1
|
533
|
-
id, table_size = main_translator.request_pref_func writes, self
|
534
|
-
func_name = pref_func_name(id)
|
535
|
-
|
536
|
-
call_c = call_to_c(func_name,
|
537
|
-
[*params_args, param_name_to_c(param_name)],
|
538
|
-
arch_prefix)
|
539
|
-
|
540
|
-
io.puts call_c, eol: ';'
|
541
|
-
|
542
|
-
register_param param_name
|
543
|
-
@param_domains[param_name] = (0..table_size - 1)
|
544
|
-
elsif writes.size > 0
|
545
|
-
cond, write_args = writes.first
|
546
|
-
emit_cond cond do
|
547
|
-
emit_write(state, *write_args)
|
548
|
-
end
|
549
|
-
end
|
550
|
-
end
|
551
|
-
|
552
|
-
def emit_read_access(state, op)
|
553
|
-
call = access_call_to_c 'read', op, "#{arch_var_name(true)}->acc",
|
554
|
-
[inst && inst_name_to_c(inst) || 'inst']
|
555
|
-
|
556
|
-
#emit_c_block "if(!#{call})" do
|
557
|
-
# emit_exit error: true
|
558
|
-
#end
|
559
|
-
io.puts call, eol: ';'
|
560
|
-
end
|
561
|
-
|
562
|
-
def access_call_to_c(name, op, acc = 'acc', params = [], eol: false)
|
563
|
-
call_to_c("#{name}_access",
|
564
|
-
[
|
565
|
-
"(#{bitmap_c_type} *) &#{acc}",
|
566
|
-
"(#{regs.c_type}) #{expr_to_c(op)}",
|
567
|
-
*params
|
568
|
-
],
|
569
|
-
indep_arch_prefix,
|
570
|
-
eol: eol)
|
571
|
-
end
|
572
|
-
|
573
|
-
def emit_write_access(_state, op)
|
574
|
-
io.puts access_call_to_c('write', op, eol: true)
|
575
|
-
end
|
576
|
-
|
577
|
-
def emit_undefined_access(_state, op)
|
578
|
-
io.puts access_call_to_c('undefined', op, eol: true)
|
579
|
-
end
|
580
|
-
|
581
|
-
def write_to_c(value, size)
|
582
|
-
if size.is_a?(Array) && value.is_a?(Array)
|
583
|
-
value_c, size_c = value.reverse.zip(size.reverse).inject(['0', 0]) do |(v_, s_), (v, s)|
|
584
|
-
[v_ + " | ((#{expr_to_c v} & ((1 << #{s}) - 1)) << #{s_})", s_ + s]
|
585
|
-
end
|
586
|
-
else
|
587
|
-
value_c =
|
588
|
-
case value
|
589
|
-
when Integer
|
590
|
-
'0x' + value.to_s(16)
|
591
|
-
else
|
592
|
-
expr_to_c value
|
593
|
-
end
|
594
|
-
|
595
|
-
size_c = expr_to_c size
|
596
|
-
end
|
597
|
-
|
598
|
-
call_to_c "write#{size_c}", [value_c], indep_arch_prefix, eol: true
|
599
|
-
end
|
600
|
-
|
601
|
-
def emit_write(_state, value, size)
|
602
|
-
io.puts write_to_c(value, size)
|
603
|
-
end
|
604
|
-
|
605
|
-
def emit_access(state, op, access)
|
606
|
-
#access.each do |mode|
|
607
|
-
# case mode
|
608
|
-
# when :r
|
609
|
-
# emit_read_access state, op
|
610
|
-
# when :w
|
611
|
-
# emit_write_access state, op
|
612
|
-
# when :u
|
613
|
-
# emit_undefined_access state, op
|
614
|
-
# else
|
615
|
-
# fail "unexpected access mode '#{rw.inspect}'"
|
616
|
-
# end
|
617
|
-
#end
|
618
|
-
end
|
619
|
-
|
620
|
-
def emit_inst_func(io, inst)
|
621
|
-
@inst = inst
|
622
|
-
with_io io do
|
623
|
-
emit_func inst.name, inst.root_state, static: false
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
|
-
def emit_called_func(io, func, id)
|
628
|
-
with_io io do
|
629
|
-
emit_func(called_func_name(func, id),
|
630
|
-
func.root_state,
|
631
|
-
{'inst' => inst_id_c_type, 'acc' => "#{acc_c_type} *"},
|
632
|
-
local_acc: false)
|
633
|
-
end
|
634
|
-
end
|
635
|
-
|
636
|
-
def emit_pref_func(io, writes, id)
|
637
|
-
with_io io do
|
638
|
-
table_var_name, _table_size = main_translator.request_permutation_table writes.size
|
639
|
-
func_name = name_to_c pref_func_name(id), arch_prefix
|
640
|
-
|
641
|
-
emit_c_block "static void\n#{func_name}(#{arch_c_type} *#{arch_var_name},"\
|
642
|
-
" #{params_c_args}, #{main_translator.param_names.c_type} order)" do
|
643
|
-
io.puts 'int i;'
|
644
|
-
emit_c_block "for(i = 0; i < #{writes.size}; i++)" do
|
645
|
-
emit_c_block "switch(#{table_var_name}[param_vals[order]][i])" do
|
646
|
-
writes.each_with_index do |write, index|
|
647
|
-
cond, write_args = write
|
648
|
-
emit_c_block "case #{index}:" do
|
649
|
-
emit_cond cond do
|
650
|
-
io.puts write_to_c(*write_args)
|
651
|
-
end
|
652
|
-
io.puts 'break;'
|
653
|
-
end
|
654
|
-
end
|
655
|
-
io.puts "default: evoasm_assert_not_reached();"
|
656
|
-
end
|
657
|
-
end
|
658
|
-
end
|
659
|
-
end
|
660
|
-
end
|
661
|
-
end
|
662
|
-
|
663
|
-
class Translator < BaseTranslator
|
664
|
-
attr_reader :params, :param_names
|
665
|
-
attr_reader :id_map, :arch
|
666
|
-
attr_reader :options
|
667
|
-
attr_reader :features, :inst_flags
|
668
|
-
attr_reader :reg_names, :exceptions
|
669
|
-
attr_reader :reg_types, :operand_types
|
670
|
-
attr_reader :bit_masks
|
671
|
-
attr_reader :insts, :regs
|
672
|
-
attr_reader :registered_param_domains
|
673
|
-
|
674
|
-
STATIC_PARAMS = %i(reg0 reg1 reg2 reg3 reg4 imm operand_size address_size)
|
675
|
-
PARAM_ALIASES = { imm0: :imm }
|
676
|
-
|
677
|
-
def initialize(arch, insts, options = {})
|
678
|
-
@arch = arch
|
679
|
-
@insts = insts
|
680
|
-
@pref_funcs = {}
|
681
|
-
@called_funcs = {}
|
682
|
-
@options = options
|
683
|
-
@registered_param_domains = Set.new
|
684
|
-
|
685
|
-
load_enums
|
686
|
-
end
|
687
|
-
|
688
|
-
def self.target_filename(arch, header: false)
|
689
|
-
"evoasm-#{arch}.#{header ? 'h' : 'c'}"
|
690
|
-
end
|
691
|
-
|
692
|
-
def self.template_path(arch, header: false)
|
693
|
-
File.join Evoasm.data, 'templates', "#{target_filename(arch, header: header)}.erb"
|
694
|
-
end
|
695
|
-
|
696
|
-
def translate!(&block)
|
697
|
-
case arch
|
698
|
-
when :x64
|
699
|
-
translate_x64(&block)
|
700
|
-
else
|
701
|
-
fail "unsupported architecture #{@arch}"
|
702
|
-
end
|
703
|
-
end
|
704
|
-
|
705
|
-
def main_translator
|
706
|
-
self
|
707
|
-
end
|
708
|
-
|
709
|
-
def register_param(name)
|
710
|
-
param_names.add name, PARAM_ALIASES[name]
|
711
|
-
end
|
712
|
-
|
713
|
-
def request_pref_func(writes, translator)
|
714
|
-
_, table_size = request_permutation_table(writes.size)
|
715
|
-
[request(@pref_funcs, writes, translator), table_size]
|
716
|
-
end
|
717
|
-
|
718
|
-
def request_func_call(func, translator)
|
719
|
-
request @called_funcs, func, translator
|
720
|
-
end
|
721
|
-
|
722
|
-
def request_permutation_table(n)
|
723
|
-
@permutation_tables ||= Hash.new { |h, k| h[k] = (0...k).to_a.permutation }
|
724
|
-
[permutation_table_var_name(n), @permutation_tables[n].size]
|
725
|
-
end
|
726
|
-
|
727
|
-
private
|
728
|
-
def load_enums
|
729
|
-
@param_names = Enum.new :param_id, STATIC_PARAMS, prefix: arch
|
730
|
-
|
731
|
-
case arch
|
732
|
-
when :x64
|
733
|
-
@features = Enum.new :feature, prefix: arch, flags: true
|
734
|
-
@inst_flags = Enum.new :inst_flag, prefix: arch, flags: true
|
735
|
-
@exceptions = Enum.new :exception_id, prefix: arch
|
736
|
-
@reg_types = Enum.new :reg_type, Evoasm::Gen::X64::REGISTERS.keys, prefix: arch
|
737
|
-
@operand_types = Enum.new :operand_type, Evoasm::Gen::X64::Inst::OPERAND_TYPES, prefix: arch
|
738
|
-
@reg_names = Enum.new :reg_id, Evoasm::Gen::X64::REGISTER_NAMES, prefix: arch
|
739
|
-
@bit_masks = Enum.new :bit_mask, %i(rest 64_127 32_63 0_31), prefix: arch, flags: true
|
740
|
-
end
|
741
|
-
end
|
742
|
-
|
743
|
-
def register_param_domain(domain)
|
744
|
-
@registered_param_domains << domain
|
745
|
-
end
|
746
|
-
|
747
|
-
def translate_x64(&block)
|
748
|
-
translate_x64_c(&block)
|
749
|
-
|
750
|
-
# NOTE: must be done after
|
751
|
-
# translating C file
|
752
|
-
# as we are collecting information
|
753
|
-
# in the translation process
|
754
|
-
translate_x64_h(&block)
|
755
|
-
end
|
756
|
-
|
757
|
-
def translate_x64_h(&block)
|
758
|
-
target_filename = self.class.target_filename(arch, header: true)
|
759
|
-
template_path = self.class.template_path(arch, header: true)
|
760
|
-
|
761
|
-
renderer = Erubis::Eruby.new(File.read(template_path))
|
762
|
-
block[target_filename, renderer.result(binding)]
|
763
|
-
end
|
764
|
-
|
765
|
-
def translate_x64_c(&block)
|
766
|
-
target_filename = self.class.target_filename(arch)
|
767
|
-
template_path = self.class.template_path(arch)
|
768
|
-
|
769
|
-
# NOTE: keep in correct order
|
770
|
-
inst_funcs = inst_funcs_to_c
|
771
|
-
pref_funcs = pref_funcs_to_c
|
772
|
-
permutation_tables = permutation_tables_to_c
|
773
|
-
called_funcs = called_funcs_to_c
|
774
|
-
insts_c = insts_to_c
|
775
|
-
inst_operands = inst_operands_to_c
|
776
|
-
inst_params = inst_params_to_c
|
777
|
-
param_domains = param_domains_to_c
|
778
|
-
|
779
|
-
renderer = Erubis::Eruby.new(File.read(template_path))
|
780
|
-
block[target_filename, renderer.result(binding)]
|
781
|
-
end
|
782
|
-
|
783
|
-
def operand_c_type
|
784
|
-
name_to_c :operand, arch_prefix
|
785
|
-
end
|
786
|
-
|
787
|
-
def param_c_type
|
788
|
-
name_to_c :arch_param
|
789
|
-
end
|
790
|
-
|
791
|
-
def inst_params_var_name(inst)
|
792
|
-
"params_#{inst.name}"
|
793
|
-
end
|
794
|
-
|
795
|
-
def insts_var_name
|
796
|
-
"_evoasm_#{arch}_insts"
|
797
|
-
end
|
798
|
-
|
799
|
-
def inst_operands_var_name(inst)
|
800
|
-
"operands_#{inst.name}"
|
801
|
-
end
|
802
|
-
|
803
|
-
def inst_param_domains_var_name(inst)
|
804
|
-
"domains_#{inst.name}"
|
805
|
-
end
|
806
|
-
|
807
|
-
def param_domain_var_name(domain)
|
808
|
-
case domain
|
809
|
-
when Range
|
810
|
-
"param_domain__#{domain.begin.to_s.tr('-', 'm')}_#{domain.end}"
|
811
|
-
when Array
|
812
|
-
"param_domain_enum__#{domain.join '_'}"
|
813
|
-
else
|
814
|
-
fail "unexpected domain type #{domain.class} (#{domain.inspect})"
|
815
|
-
end
|
816
|
-
end
|
817
|
-
|
818
|
-
def permutation_table_var_name(n)
|
819
|
-
"permutations#{n}"
|
820
|
-
end
|
821
|
-
|
822
|
-
def inst_encode_func_name(inst)
|
823
|
-
name_to_c inst.name, arch_prefix
|
824
|
-
end
|
825
|
-
|
826
|
-
def inst_funcs_to_c(io = StrIO.new)
|
827
|
-
@inst_translators = insts.map do |inst|
|
828
|
-
@features.add_all inst.features
|
829
|
-
@inst_flags.add_all inst.flags
|
830
|
-
@exceptions.add_all inst.exceptions
|
831
|
-
|
832
|
-
inst_translator = FuncTranslator.new arch, self
|
833
|
-
inst_translator.emit_inst_func io, inst
|
834
|
-
|
835
|
-
inst_translator
|
836
|
-
end
|
837
|
-
|
838
|
-
io.string
|
839
|
-
end
|
840
|
-
|
841
|
-
def permutation_tables_to_c(io = StrIO.new)
|
842
|
-
Hash(@permutation_tables).each do |n, perms|
|
843
|
-
io.puts "static int #{permutation_table_var_name n}"\
|
844
|
-
"[#{perms.size}][#{perms.first.size}] = {"
|
845
|
-
|
846
|
-
perms.each do |perm|
|
847
|
-
io.puts " {#{perm.join ', '}},"
|
848
|
-
end
|
849
|
-
io.puts '};'
|
850
|
-
io.puts
|
851
|
-
end
|
852
|
-
|
853
|
-
io.string
|
854
|
-
end
|
855
|
-
|
856
|
-
def called_funcs_to_c(io = StrIO.new)
|
857
|
-
@called_funcs.each do |func, (id, translators)|
|
858
|
-
func_translator = FuncTranslator.new arch, self
|
859
|
-
func_translator.emit_called_func io, func, id
|
860
|
-
|
861
|
-
translators.each do |translator|
|
862
|
-
translator.merge_params func_translator.registered_params
|
863
|
-
end
|
864
|
-
end
|
865
|
-
|
866
|
-
io.string
|
867
|
-
end
|
868
|
-
|
869
|
-
def inst_to_c(io, inst, params)
|
870
|
-
io.puts '{'
|
871
|
-
io.indent do
|
872
|
-
io.puts '{'
|
873
|
-
io.indent do
|
874
|
-
io.puts inst_name_to_c(inst), eol: ','
|
875
|
-
io.puts params.size, eol: ','
|
876
|
-
if params.empty?
|
877
|
-
io.puts "NULL,"
|
878
|
-
else
|
879
|
-
io.puts "(#{param_c_type} *)" + inst_params_var_name(inst), eol: ','
|
880
|
-
end
|
881
|
-
io.puts '(evoasm_inst_encode_func)' + inst_encode_func_name(inst), eol: ','
|
882
|
-
end
|
883
|
-
io.puts '},'
|
884
|
-
|
885
|
-
io.puts "#{features_bitmap(inst)}ull", eol: ','
|
886
|
-
if inst.operands.empty?
|
887
|
-
io.puts 'NULL,'
|
888
|
-
else
|
889
|
-
io.puts "(#{operand_c_type} *)#{inst_operands_var_name inst}", eol: ','
|
890
|
-
end
|
891
|
-
io.puts inst.operands.size, eol: ','
|
892
|
-
io.puts exceptions_bitmap(inst), eol: ','
|
893
|
-
io.puts inst_flags_to_c(inst)
|
894
|
-
end
|
895
|
-
io.puts '},'
|
896
|
-
end
|
897
|
-
|
898
|
-
def insts_to_c(io = StrIO.new)
|
899
|
-
io.puts "static const evoasm_x64_inst #{insts_var_name}[] = {"
|
900
|
-
@inst_translators.each do |translator|
|
901
|
-
inst_to_c io, translator.inst, translator.registered_params
|
902
|
-
end
|
903
|
-
io.puts '};'
|
904
|
-
|
905
|
-
io.string
|
906
|
-
end
|
907
|
-
|
908
|
-
def inst_param_to_c(io, inst, params, param_domains)
|
909
|
-
if !params.empty?
|
910
|
-
io.puts "static const #{param_c_type} #{inst_params_var_name inst}[] = {"
|
911
|
-
io.indent do
|
912
|
-
params.each do |param|
|
913
|
-
next if local_param? param
|
914
|
-
|
915
|
-
param_domain = param_domains[param] || inst.param_domain(param)
|
916
|
-
register_param_domain param_domain
|
917
|
-
|
918
|
-
io.puts '{'
|
919
|
-
io.indent do
|
920
|
-
io.puts param_name_to_c(param), eol: ','
|
921
|
-
io.puts '(evoasm_domain *) &' + param_domain_var_name(param_domain)
|
922
|
-
end
|
923
|
-
io.puts '},'
|
924
|
-
end
|
925
|
-
end
|
926
|
-
io.puts '};'
|
927
|
-
io.puts
|
928
|
-
end
|
929
|
-
end
|
930
|
-
|
931
|
-
def inst_params_to_c(io = StrIO.new)
|
932
|
-
@inst_translators.each do |translator|
|
933
|
-
inst_param_to_c io, translator.inst, translator.registered_params, translator.param_domains
|
934
|
-
end
|
935
|
-
|
936
|
-
io.string
|
937
|
-
end
|
938
|
-
|
939
|
-
def inst_operand_to_c(translator, op, io = StrIO.new, eol:)
|
940
|
-
io.puts '{'
|
941
|
-
io.indent do
|
942
|
-
io.puts op.access.include?(:r) ? '1' : '0', eol: ','
|
943
|
-
io.puts op.access.include?(:w) ? '1' : '0', eol: ','
|
944
|
-
io.puts op.access.include?(:u) ? '1' : '0', eol: ','
|
945
|
-
io.puts op.access.include?(:c) ? '1' : '0', eol: ','
|
946
|
-
io.puts op.implicit? ? '1' : '0', eol: ','
|
947
|
-
|
948
|
-
params = translator.registered_params.reject{|p| local_param? p}
|
949
|
-
if op.param
|
950
|
-
param_idx = params.index(op.param) or \
|
951
|
-
raise "param #{op.param} not found in #{translator.params.inspect}" \
|
952
|
-
" (#{translator.inst.mnem}/#{translator.inst.index})"
|
953
|
-
|
954
|
-
io.puts param_idx, eol: ','
|
955
|
-
else
|
956
|
-
io.puts params.size, eol: ','
|
957
|
-
end
|
958
|
-
|
959
|
-
io.puts operand_type_to_c(op.type), eol: ','
|
960
|
-
|
961
|
-
if op.size
|
962
|
-
io.puts operand_size_to_c(op.size), eol: ','
|
963
|
-
else
|
964
|
-
io.puts 'EVOASM_N_OPERAND_SIZES', eol: ','
|
965
|
-
end
|
966
|
-
|
967
|
-
if op.reg
|
968
|
-
io.puts reg_name_to_c(op.reg), eol: ','
|
969
|
-
else
|
970
|
-
io.puts reg_names.n_elem_to_c, eol: ','
|
971
|
-
end
|
972
|
-
|
973
|
-
if op.reg_type
|
974
|
-
io.puts reg_type_to_c(op.reg_type), eol: ','
|
975
|
-
else
|
976
|
-
io.puts reg_types.n_elem_to_c, eol: ','
|
977
|
-
end
|
978
|
-
|
979
|
-
if op.accessed_bits.key? :w
|
980
|
-
io.puts bit_mask_to_c(op.accessed_bits[:w])
|
981
|
-
else
|
982
|
-
io.puts bit_masks.all_to_c
|
983
|
-
end
|
984
|
-
end
|
985
|
-
io.puts '}', eol: eol
|
986
|
-
end
|
987
|
-
|
988
|
-
def inst_operands_to_c(io = StrIO.new)
|
989
|
-
@inst_translators.each do |translator|
|
990
|
-
if !translator.inst.operands.empty?
|
991
|
-
io.puts "static const #{operand_c_type} #{inst_operands_var_name translator.inst}[] = {"
|
992
|
-
io.indent do
|
993
|
-
translator.inst.operands.each do |op|
|
994
|
-
inst_operand_to_c(translator, op, io, eol: ',')
|
995
|
-
end
|
996
|
-
end
|
997
|
-
io.puts '};'
|
998
|
-
io.puts
|
999
|
-
end
|
1000
|
-
end
|
1001
|
-
|
1002
|
-
io.string
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
ENUM_MAX_LENGTH = 32
|
1006
|
-
def param_domain_to_c(io, domain, index)
|
1007
|
-
domain_c =
|
1008
|
-
case domain
|
1009
|
-
when (:INT64_MIN..:INT64_MAX)
|
1010
|
-
"{EVOASM_DOMAIN_TYPE_INTERVAL64, #{index}, #{0}, #{0}}"
|
1011
|
-
when Range
|
1012
|
-
min_c = expr_to_c domain.begin
|
1013
|
-
max_c = expr_to_c domain.end
|
1014
|
-
"{EVOASM_DOMAIN_TYPE_INTERVAL, #{index}, #{min_c}, #{max_c}}"
|
1015
|
-
when Array
|
1016
|
-
if domain.size > ENUM_MAX_LENGTH
|
1017
|
-
raise 'enum exceeds maximal enum length of'
|
1018
|
-
end
|
1019
|
-
values_c = "#{domain.map { |expr| expr_to_c expr }.join ', '}"
|
1020
|
-
"{EVOASM_DOMAIN_TYPE_ENUM, #{index}, #{domain.length}, {#{values_c}}}"
|
1021
|
-
end
|
1022
|
-
|
1023
|
-
domain_c_type =
|
1024
|
-
case domain
|
1025
|
-
when Range
|
1026
|
-
'evoasm_interval'
|
1027
|
-
when Array
|
1028
|
-
"evoasm_enum#{domain.size}"
|
1029
|
-
end
|
1030
|
-
io.puts "static const #{domain_c_type} #{param_domain_var_name domain} = #{domain_c};"
|
1031
|
-
end
|
1032
|
-
|
1033
|
-
def param_domains_to_c(io = StrIO.new)
|
1034
|
-
registered_param_domains.each_with_index do |domain, index|
|
1035
|
-
param_domain_to_c io, domain, index
|
1036
|
-
end
|
1037
|
-
|
1038
|
-
io.puts "const uint16_t evoasm_n_domains = #{registered_param_domains.size};"
|
1039
|
-
|
1040
|
-
io.string
|
1041
|
-
end
|
1042
|
-
|
1043
|
-
def request(hash, key, translator)
|
1044
|
-
id, translators = hash[key]
|
1045
|
-
if id.nil?
|
1046
|
-
id = hash.size
|
1047
|
-
translators = []
|
1048
|
-
|
1049
|
-
hash[key] = [id, translators]
|
1050
|
-
end
|
1051
|
-
|
1052
|
-
translators << translator
|
1053
|
-
id
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
def pref_funcs_to_c(io = StrIO.new)
|
1057
|
-
@pref_funcs.each do |writes, (id, translators)|
|
1058
|
-
func_translator = FuncTranslator.new arch, self
|
1059
|
-
func_translator.emit_pref_func io, writes, id
|
1060
|
-
|
1061
|
-
translators.each do |translator|
|
1062
|
-
translator.merge_params func_translator.registered_params
|
1063
|
-
end
|
1064
|
-
end
|
1065
|
-
|
1066
|
-
io.string
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
def inst_flags_to_c(inst)
|
1070
|
-
if inst.flags.empty?
|
1071
|
-
"0"
|
1072
|
-
else
|
1073
|
-
inst.flags.map { |flag| inst_flag_to_c flag }
|
1074
|
-
.join ' | '
|
1075
|
-
end
|
1076
|
-
end
|
1077
|
-
|
1078
|
-
def features_bitmap(inst)
|
1079
|
-
bitmap(features) do |flag, index|
|
1080
|
-
inst.features.include?(flag)
|
1081
|
-
end
|
1082
|
-
end
|
1083
|
-
|
1084
|
-
def exceptions_bitmap(inst)
|
1085
|
-
bitmap(exceptions) do |flag, index|
|
1086
|
-
inst.exceptions.include?(flag)
|
1087
|
-
end
|
1088
|
-
end
|
1089
|
-
|
1090
|
-
def bitmap(enum, &block)
|
1091
|
-
enum.keys.each_with_index.inject(0) do |acc, (flag, index)|
|
1092
|
-
if block[flag, index]
|
1093
|
-
acc | (1 << index)
|
1094
|
-
else
|
1095
|
-
acc
|
1096
|
-
end
|
1097
|
-
end
|
1098
|
-
end
|
1099
|
-
|
1100
|
-
end
|
1101
|
-
end
|
1102
|
-
end
|