evoasm 0.0.2.pre7
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 +7 -0
- data/.gemrelease +2 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/Gemfile.rake +8 -0
- data/Gemfile.rake.lock +51 -0
- data/LICENSE.txt +373 -0
- data/Makefile +6 -0
- data/README.md +43 -0
- data/Rakefile +128 -0
- data/bin/gdb +2 -0
- data/data/tables/README.md +19 -0
- data/data/tables/x64.csv +1684 -0
- data/data/templates/evoasm-x64.c.erb +319 -0
- data/data/templates/evoasm-x64.h.erb +126 -0
- data/evoasm.gemspec +30 -0
- data/examples/abs.yml +20 -0
- data/examples/popcnt.yml +17 -0
- data/examples/sym_reg.yml +26 -0
- data/exe/evoasm-search +13 -0
- data/ext/evoasm_ext/evoasm-alloc.c +145 -0
- data/ext/evoasm_ext/evoasm-alloc.h +59 -0
- data/ext/evoasm_ext/evoasm-arch.c +44 -0
- data/ext/evoasm_ext/evoasm-arch.h +161 -0
- data/ext/evoasm_ext/evoasm-bitmap.h +114 -0
- data/ext/evoasm_ext/evoasm-buf.c +130 -0
- data/ext/evoasm_ext/evoasm-buf.h +47 -0
- data/ext/evoasm_ext/evoasm-error.c +31 -0
- data/ext/evoasm_ext/evoasm-error.h +75 -0
- data/ext/evoasm_ext/evoasm-free-list.c.tmpl +121 -0
- data/ext/evoasm_ext/evoasm-free-list.h.tmpl +86 -0
- data/ext/evoasm_ext/evoasm-log.c +108 -0
- data/ext/evoasm_ext/evoasm-log.h +69 -0
- data/ext/evoasm_ext/evoasm-misc.c +23 -0
- data/ext/evoasm_ext/evoasm-misc.h +282 -0
- data/ext/evoasm_ext/evoasm-param.h +37 -0
- data/ext/evoasm_ext/evoasm-search.c +2145 -0
- data/ext/evoasm_ext/evoasm-search.h +214 -0
- data/ext/evoasm_ext/evoasm-util.h +40 -0
- data/ext/evoasm_ext/evoasm-x64.c +275624 -0
- data/ext/evoasm_ext/evoasm-x64.h +5436 -0
- data/ext/evoasm_ext/evoasm.c +7 -0
- data/ext/evoasm_ext/evoasm.h +23 -0
- data/ext/evoasm_ext/evoasm_ext.c +1757 -0
- data/ext/evoasm_ext/extconf.rb +31 -0
- data/lib/evoasm/cli/search.rb +127 -0
- data/lib/evoasm/cli.rb +6 -0
- data/lib/evoasm/core_ext/array.rb +9 -0
- data/lib/evoasm/core_ext/integer.rb +10 -0
- data/lib/evoasm/core_ext/kwstruct.rb +13 -0
- data/lib/evoasm/core_ext/range.rb +5 -0
- data/lib/evoasm/core_ext.rb +1 -0
- data/lib/evoasm/error.rb +20 -0
- data/lib/evoasm/examples.rb +27 -0
- data/lib/evoasm/gen/enum.rb +169 -0
- data/lib/evoasm/gen/name_util.rb +80 -0
- data/lib/evoasm/gen/state.rb +176 -0
- data/lib/evoasm/gen/state_dsl.rb +152 -0
- data/lib/evoasm/gen/strio.rb +27 -0
- data/lib/evoasm/gen/translator.rb +1102 -0
- data/lib/evoasm/gen/version.rb +5 -0
- data/lib/evoasm/gen/x64/funcs.rb +495 -0
- data/lib/evoasm/gen/x64/inst.rb +781 -0
- data/lib/evoasm/gen/x64.rb +237 -0
- data/lib/evoasm/gen.rb +8 -0
- data/lib/evoasm/program.rb +23 -0
- data/lib/evoasm/search.rb +40 -0
- data/lib/evoasm/tasks/gen_task.rb +86 -0
- data/lib/evoasm/tasks/template_task.rb +52 -0
- data/lib/evoasm/version.rb +3 -0
- data/lib/evoasm.rb +22 -0
- data/test/test_helper.rb +1 -0
- data/test/x64/test_helper.rb +19 -0
- data/test/x64/x64_test.rb +87 -0
- metadata +221 -0
@@ -0,0 +1,1102 @@
|
|
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
|