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,495 @@
|
|
1
|
+
require 'evoasm/gen/state_dsl'
|
2
|
+
require 'evoasm/core_ext/kwstruct'
|
3
|
+
|
4
|
+
module Evoasm::Gen
|
5
|
+
module X64
|
6
|
+
VEX = KwStruct.new :rex_w, :reg_reg_param, :rm_reg_param, :vex_m, :vex_v, :vex_l, :vex_p do
|
7
|
+
include StateDSL
|
8
|
+
|
9
|
+
state def two_byte_vex
|
10
|
+
state do
|
11
|
+
log :trace, 'writing vex'
|
12
|
+
write 0b11000101, 8
|
13
|
+
write [
|
14
|
+
[:neg, :rex_r],
|
15
|
+
[:neg, vex_v || :vex_v],
|
16
|
+
(vex_l || :vex_l),
|
17
|
+
vex_p
|
18
|
+
], [1, 4, 1, 2]
|
19
|
+
ret
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
state def three_byte_vex
|
24
|
+
state do
|
25
|
+
log :trace, 'writing vex'
|
26
|
+
write 0b11000100, 8
|
27
|
+
write [[:neg, :rex_r],
|
28
|
+
[:neg, :rex_x],
|
29
|
+
[:neg, :rex_b],
|
30
|
+
vex_m], [1, 1, 1, 5]
|
31
|
+
write [rex_w || :rex_w,
|
32
|
+
[:neg, vex_v || :vex_v],
|
33
|
+
vex_l || :vex_l,
|
34
|
+
vex_p], [1, 4, 1, 2]
|
35
|
+
ret
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def zero_rex?
|
40
|
+
cond =
|
41
|
+
[:and,
|
42
|
+
[:eq, :rex_x, 0b0],
|
43
|
+
[:eq, :rex_b, 0b0]
|
44
|
+
]
|
45
|
+
|
46
|
+
cond << [:eq, :rex_w, 0b0] unless rex_w == 0x0
|
47
|
+
|
48
|
+
cond
|
49
|
+
end
|
50
|
+
|
51
|
+
state def root_state
|
52
|
+
state do
|
53
|
+
comment 'VEX'
|
54
|
+
|
55
|
+
# assume rex_w and vex_l set
|
56
|
+
# default unset 0 is ok for both
|
57
|
+
if vex_m == 0x01 && rex_w != 0x1
|
58
|
+
to_if :and, zero_rex?, [:false?, :force_long_vex?], two_byte_vex
|
59
|
+
else_to three_byte_vex
|
60
|
+
else
|
61
|
+
to three_byte_vex
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
REX = KwStruct.new :rex_w, :reg_reg_param, :rm_reg_param, :force, :rm_reg_type, :modrm do
|
68
|
+
include StateDSL
|
69
|
+
|
70
|
+
alias_method :modrm?, :modrm
|
71
|
+
# reg_reg_param
|
72
|
+
# and rm_reg_param
|
73
|
+
# are REGISTERS
|
74
|
+
# and NOT register ids
|
75
|
+
# or bitfield values
|
76
|
+
|
77
|
+
def rex_bit(reg)
|
78
|
+
[:div, [:reg_code, reg], 8]
|
79
|
+
end
|
80
|
+
|
81
|
+
def base_or_index?
|
82
|
+
modrm? && rm_reg_type != :reg
|
83
|
+
end
|
84
|
+
|
85
|
+
def need_rex?
|
86
|
+
cond = [:or]
|
87
|
+
cond << [:neq, rex_bit(reg_reg_param), 0] if reg_reg_param
|
88
|
+
cond << [:and, [:set?, rm_reg_param], [:neq, rex_bit(rm_reg_param), 0]] if rm_reg_param
|
89
|
+
|
90
|
+
cond << [:and, [:set?, :reg_base], [:neq, rex_bit(:reg_base), 0]] if base_or_index?
|
91
|
+
cond << [:and, [:set?, :reg_index], [:neq, rex_bit(:reg_index), 0]] if base_or_index?
|
92
|
+
|
93
|
+
cond == [:or] ? false : cond
|
94
|
+
end
|
95
|
+
|
96
|
+
state def rex_b
|
97
|
+
state do
|
98
|
+
log :trace, 'setting rex_b... modrm_rm='
|
99
|
+
|
100
|
+
#FIXME: can REX.b ever be ignored ?
|
101
|
+
#set :_rex_b, :rex_b
|
102
|
+
#to write_rex
|
103
|
+
|
104
|
+
rex_b_rm_reg = proc do
|
105
|
+
set :_rex_b, rex_bit(rm_reg_param)
|
106
|
+
to write_rex
|
107
|
+
end
|
108
|
+
|
109
|
+
rex_b_reg_reg = proc do
|
110
|
+
set :_rex_b, rex_bit(reg_reg_param)
|
111
|
+
to write_rex
|
112
|
+
end
|
113
|
+
|
114
|
+
rex_b_base_reg = proc do
|
115
|
+
log :trace, 'setting rex_b from base'
|
116
|
+
set :_rex_b, rex_bit(:reg_base)
|
117
|
+
to write_rex
|
118
|
+
end
|
119
|
+
|
120
|
+
if !modrm?
|
121
|
+
if reg_reg_param
|
122
|
+
rex_b_reg_reg[]
|
123
|
+
else
|
124
|
+
fail
|
125
|
+
end
|
126
|
+
else
|
127
|
+
case rm_reg_type
|
128
|
+
when :reg
|
129
|
+
log :trace, 'setting rex_b from modrm_rm'
|
130
|
+
rex_b_rm_reg[]
|
131
|
+
when :rm
|
132
|
+
to_if :set?, :reg_base, &rex_b_base_reg
|
133
|
+
else_to(&rex_b_rm_reg)
|
134
|
+
when :mem
|
135
|
+
rex_b_base_reg[]
|
136
|
+
else
|
137
|
+
fail
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
state def rex_rx
|
144
|
+
state do
|
145
|
+
# MI and other encodings
|
146
|
+
# do not use the MODRM.reg field
|
147
|
+
# so the corresponding REX bit
|
148
|
+
# is ignored
|
149
|
+
|
150
|
+
set_rex_r_free = proc do
|
151
|
+
set :_rex_r, :rex_r
|
152
|
+
end
|
153
|
+
|
154
|
+
rex_x_free = proc do
|
155
|
+
set :_rex_x, :rex_x
|
156
|
+
to rex_b
|
157
|
+
end
|
158
|
+
|
159
|
+
rex_x_index = proc do
|
160
|
+
set :_rex_x, rex_bit(:reg_index)
|
161
|
+
log :trace, 'rex_b... A'
|
162
|
+
to rex_b
|
163
|
+
end
|
164
|
+
|
165
|
+
if modrm?
|
166
|
+
if reg_reg_param
|
167
|
+
set :_rex_r, rex_bit(reg_reg_param)
|
168
|
+
else
|
169
|
+
set_rex_r_free[]
|
170
|
+
end
|
171
|
+
|
172
|
+
case rm_reg_type
|
173
|
+
when :reg
|
174
|
+
rex_x_free[]
|
175
|
+
when :rm
|
176
|
+
to_if :set?, :reg_index, &rex_x_index
|
177
|
+
else_to(&rex_x_free)
|
178
|
+
when :mem
|
179
|
+
rex_x_index[]
|
180
|
+
else
|
181
|
+
fail
|
182
|
+
end
|
183
|
+
else
|
184
|
+
set_rex_r_free[]
|
185
|
+
rex_x_free[]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
state def root_state
|
191
|
+
if force
|
192
|
+
rex_rx
|
193
|
+
else
|
194
|
+
# rex?: output REX even if not force
|
195
|
+
# need_rex?: REX is required (use of ext. reg.)
|
196
|
+
state do
|
197
|
+
to_if :or, [:true?, :force_rex?], need_rex?, rex_rx
|
198
|
+
else_to do
|
199
|
+
ret
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
state def write_rex
|
206
|
+
state do
|
207
|
+
comment 'REX prefix'
|
208
|
+
rex_w = self.rex_w
|
209
|
+
|
210
|
+
# assume rex_w is set if the
|
211
|
+
# attr rex_w is nil
|
212
|
+
# unset default 0 is ok
|
213
|
+
rex_w ||= :rex_w
|
214
|
+
|
215
|
+
write [0b0100, rex_w, :_rex_r, :_rex_x, :_rex_b], [4, 1, 1, 1, 1]
|
216
|
+
log :trace, 'writing rex % % % %', :rex_w, :_rex_r, :_rex_x, :_rex_b
|
217
|
+
|
218
|
+
ret
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
ModRMSIB = KwStruct.new :reg_reg_param, :rm_reg_param, :rm_type, :modrm_reg, :rm_reg_access,
|
224
|
+
:reg_reg_access do
|
225
|
+
include StateDSL
|
226
|
+
|
227
|
+
def reg_bits(reg, reg_code: false)
|
228
|
+
reg_code = if reg_code
|
229
|
+
reg
|
230
|
+
else
|
231
|
+
[:reg_code, reg]
|
232
|
+
end
|
233
|
+
[:mod, reg_code, 8]
|
234
|
+
end
|
235
|
+
|
236
|
+
def write_modrm(mod, rm)
|
237
|
+
reg = if modrm_reg
|
238
|
+
modrm_reg
|
239
|
+
elsif reg_reg_param
|
240
|
+
# register, use register parameter specified
|
241
|
+
# in reg_reg_param
|
242
|
+
reg_bits(reg_reg_param)
|
243
|
+
else
|
244
|
+
# ModRM.reg is free, use a parameter
|
245
|
+
reg_bits(:modrm_reg, reg_code: true)
|
246
|
+
end
|
247
|
+
|
248
|
+
write [mod, reg, rm], [2, 3, 3]
|
249
|
+
end
|
250
|
+
|
251
|
+
def write_sib(scale = nil, index = nil, base = nil)
|
252
|
+
write [
|
253
|
+
scale || [:log2, :scale],
|
254
|
+
index || reg_bits(:_reg_index),
|
255
|
+
base || reg_bits(:reg_base)
|
256
|
+
], [2, 3, 3]
|
257
|
+
end
|
258
|
+
|
259
|
+
def zero_disp?
|
260
|
+
# NOTE: unset disp defaults to 0 as well
|
261
|
+
[:eq, :disp, 0]
|
262
|
+
end
|
263
|
+
|
264
|
+
def matching_disp_size?
|
265
|
+
[:or, [:unset?, :disp_size], [:eq, :disp_size, [:disp_size]]]
|
266
|
+
end
|
267
|
+
|
268
|
+
def disp_fits?(size)
|
269
|
+
[:ltq, [:disp_size], size]
|
270
|
+
end
|
271
|
+
|
272
|
+
def disp?(size)
|
273
|
+
[:and,
|
274
|
+
disp_fits?(size),
|
275
|
+
matching_disp_size?
|
276
|
+
]
|
277
|
+
end
|
278
|
+
|
279
|
+
def vsib?
|
280
|
+
rm_type == :vsib
|
281
|
+
end
|
282
|
+
|
283
|
+
def direct_only?
|
284
|
+
rm_type == :reg
|
285
|
+
end
|
286
|
+
|
287
|
+
def indirect_only?
|
288
|
+
rm_type == :mem
|
289
|
+
end
|
290
|
+
|
291
|
+
def modrm_sib_disp(rm:, sib:)
|
292
|
+
to_if :and, zero_disp?,
|
293
|
+
matching_disp_size?,
|
294
|
+
[reg_code_not_in?(:reg_base, 5, 13)] do
|
295
|
+
write_modrm 0b00, rm
|
296
|
+
write_sib if sib
|
297
|
+
ret
|
298
|
+
end
|
299
|
+
else_to do
|
300
|
+
to_if :and, disp_fits?(8), [:false?, :force_disp32?] do
|
301
|
+
write_modrm 0b01, rm
|
302
|
+
write_sib if sib
|
303
|
+
write :disp, 8
|
304
|
+
ret
|
305
|
+
end
|
306
|
+
else_to do
|
307
|
+
write_modrm 0b10, rm
|
308
|
+
write_sib if sib
|
309
|
+
write :disp, 32
|
310
|
+
ret
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
state def _scale_index_base
|
316
|
+
state do
|
317
|
+
modrm_sib_disp rm: 0b100, sib: true
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def index_encodable?
|
322
|
+
[:neq, [:reg_code, :reg_index], 0b0100]
|
323
|
+
end
|
324
|
+
|
325
|
+
state def scale_index_base
|
326
|
+
state do
|
327
|
+
log :trace, 'scale, index, base'
|
328
|
+
set :_reg_index, :reg_index
|
329
|
+
|
330
|
+
if vsib?
|
331
|
+
to _scale_index_base
|
332
|
+
else
|
333
|
+
to_if index_encodable?, _scale_index_base
|
334
|
+
else_to do
|
335
|
+
# not encodable
|
336
|
+
error :not_encodable, "index not encodable", param: :reg_index
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
state def disp_only
|
343
|
+
state do
|
344
|
+
log :trace, 'disp only'
|
345
|
+
set :_reg_index, :reg_index
|
346
|
+
write_modrm 0b00, 0b100
|
347
|
+
write_sib nil, nil, 0b101
|
348
|
+
write :disp, 32
|
349
|
+
ret
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
state def index_only
|
354
|
+
state do
|
355
|
+
log :trace, 'index only'
|
356
|
+
|
357
|
+
if vsib?
|
358
|
+
cond = true
|
359
|
+
else
|
360
|
+
cond = index_encodable?
|
361
|
+
end
|
362
|
+
|
363
|
+
to_if cond do
|
364
|
+
set :_reg_index, :reg_index
|
365
|
+
write_modrm 0b00, 0b100
|
366
|
+
write_sib nil, nil, 0b101
|
367
|
+
write :disp, 32
|
368
|
+
ret
|
369
|
+
end
|
370
|
+
if cond != true
|
371
|
+
else_to do
|
372
|
+
error :not_encodable, "index not encodable (0b0100)", param: :reg_index
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
state def base_only_w_sib
|
379
|
+
state do
|
380
|
+
# need index to encode as 0b100 (RSP, ESP, SP)
|
381
|
+
set :_reg_index, :SP
|
382
|
+
to _scale_index_base
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
def ip_base?
|
387
|
+
[:eq, :reg_base, :IP]
|
388
|
+
end
|
389
|
+
|
390
|
+
def reg_code_not_in?(reg, *ids)
|
391
|
+
[:not_in?, [:reg_code, reg], *ids]
|
392
|
+
end
|
393
|
+
|
394
|
+
state def base_only_wo_sib
|
395
|
+
state do
|
396
|
+
modrm_sib_disp rm: reg_bits(:reg_base), sib: false
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
state def base_only
|
401
|
+
state do
|
402
|
+
log :trace, 'base only'
|
403
|
+
to_if ip_base? do
|
404
|
+
write_modrm 0b00, 0b101
|
405
|
+
write :disp, 32
|
406
|
+
ret
|
407
|
+
end
|
408
|
+
else_to do
|
409
|
+
to_if :and, [:false?, :force_sib?], reg_code_not_in?(:reg_base, 4, 12), base_only_wo_sib
|
410
|
+
else_to base_only_w_sib
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
def no_index?
|
416
|
+
[:unset?, :reg_index]
|
417
|
+
end
|
418
|
+
|
419
|
+
def no_base?
|
420
|
+
[:unset?, :reg_base]
|
421
|
+
end
|
422
|
+
|
423
|
+
state def indirect
|
424
|
+
state do
|
425
|
+
log :trace, 'indirect addressing'
|
426
|
+
# VSIB does not allow to omit index
|
427
|
+
if vsib?
|
428
|
+
to_if no_base? do
|
429
|
+
to_if :set?, :reg_index, index_only
|
430
|
+
else_to do
|
431
|
+
error :missing_param, param: :reg_index
|
432
|
+
end
|
433
|
+
end
|
434
|
+
else_to scale_index_base
|
435
|
+
else
|
436
|
+
to_if no_base? do
|
437
|
+
to_if no_index? do
|
438
|
+
to_if :set?, :disp, disp_only
|
439
|
+
else_to do
|
440
|
+
error :missing_param, param: :disp
|
441
|
+
end
|
442
|
+
end
|
443
|
+
else_to index_only
|
444
|
+
end
|
445
|
+
else_to do
|
446
|
+
to_if no_index?, base_only
|
447
|
+
else_to scale_index_base
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def direct
|
454
|
+
state do
|
455
|
+
access rm_reg_param, rm_reg_access if rm_reg_param
|
456
|
+
|
457
|
+
write_modrm 0b11, reg_bits(rm_reg_param)
|
458
|
+
ret
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
def indirect?
|
463
|
+
[:or,
|
464
|
+
[:set?, :reg_base],
|
465
|
+
[:set?, :reg_index],
|
466
|
+
[:set?, :disp]
|
467
|
+
]
|
468
|
+
end
|
469
|
+
|
470
|
+
state def root_state
|
471
|
+
state do
|
472
|
+
comment 'ModRM'
|
473
|
+
log :trace, 'ModRM'
|
474
|
+
|
475
|
+
access reg_reg_param, reg_reg_access if reg_reg_param
|
476
|
+
|
477
|
+
if direct_only?
|
478
|
+
to direct
|
479
|
+
else
|
480
|
+
to_if indirect?, indirect
|
481
|
+
|
482
|
+
# VSIB does not allow this
|
483
|
+
if vsib? || indirect_only?
|
484
|
+
else_to do
|
485
|
+
error :not_encodable, (vsib? ? "VSIB does not allow indirect addressing" : "indirect addressing not allowed")
|
486
|
+
end
|
487
|
+
else
|
488
|
+
else_to direct
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|