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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gemrelease +2 -0
  3. data/.gitignore +16 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.rake +8 -0
  6. data/Gemfile.rake.lock +51 -0
  7. data/LICENSE.txt +373 -0
  8. data/Makefile +6 -0
  9. data/README.md +43 -0
  10. data/Rakefile +128 -0
  11. data/bin/gdb +2 -0
  12. data/data/tables/README.md +19 -0
  13. data/data/tables/x64.csv +1684 -0
  14. data/data/templates/evoasm-x64.c.erb +319 -0
  15. data/data/templates/evoasm-x64.h.erb +126 -0
  16. data/evoasm.gemspec +30 -0
  17. data/examples/abs.yml +20 -0
  18. data/examples/popcnt.yml +17 -0
  19. data/examples/sym_reg.yml +26 -0
  20. data/exe/evoasm-search +13 -0
  21. data/ext/evoasm_ext/evoasm-alloc.c +145 -0
  22. data/ext/evoasm_ext/evoasm-alloc.h +59 -0
  23. data/ext/evoasm_ext/evoasm-arch.c +44 -0
  24. data/ext/evoasm_ext/evoasm-arch.h +161 -0
  25. data/ext/evoasm_ext/evoasm-bitmap.h +114 -0
  26. data/ext/evoasm_ext/evoasm-buf.c +130 -0
  27. data/ext/evoasm_ext/evoasm-buf.h +47 -0
  28. data/ext/evoasm_ext/evoasm-error.c +31 -0
  29. data/ext/evoasm_ext/evoasm-error.h +75 -0
  30. data/ext/evoasm_ext/evoasm-free-list.c.tmpl +121 -0
  31. data/ext/evoasm_ext/evoasm-free-list.h.tmpl +86 -0
  32. data/ext/evoasm_ext/evoasm-log.c +108 -0
  33. data/ext/evoasm_ext/evoasm-log.h +69 -0
  34. data/ext/evoasm_ext/evoasm-misc.c +23 -0
  35. data/ext/evoasm_ext/evoasm-misc.h +282 -0
  36. data/ext/evoasm_ext/evoasm-param.h +37 -0
  37. data/ext/evoasm_ext/evoasm-search.c +2145 -0
  38. data/ext/evoasm_ext/evoasm-search.h +214 -0
  39. data/ext/evoasm_ext/evoasm-util.h +40 -0
  40. data/ext/evoasm_ext/evoasm-x64.c +275624 -0
  41. data/ext/evoasm_ext/evoasm-x64.h +5436 -0
  42. data/ext/evoasm_ext/evoasm.c +7 -0
  43. data/ext/evoasm_ext/evoasm.h +23 -0
  44. data/ext/evoasm_ext/evoasm_ext.c +1757 -0
  45. data/ext/evoasm_ext/extconf.rb +31 -0
  46. data/lib/evoasm/cli/search.rb +127 -0
  47. data/lib/evoasm/cli.rb +6 -0
  48. data/lib/evoasm/core_ext/array.rb +9 -0
  49. data/lib/evoasm/core_ext/integer.rb +10 -0
  50. data/lib/evoasm/core_ext/kwstruct.rb +13 -0
  51. data/lib/evoasm/core_ext/range.rb +5 -0
  52. data/lib/evoasm/core_ext.rb +1 -0
  53. data/lib/evoasm/error.rb +20 -0
  54. data/lib/evoasm/examples.rb +27 -0
  55. data/lib/evoasm/gen/enum.rb +169 -0
  56. data/lib/evoasm/gen/name_util.rb +80 -0
  57. data/lib/evoasm/gen/state.rb +176 -0
  58. data/lib/evoasm/gen/state_dsl.rb +152 -0
  59. data/lib/evoasm/gen/strio.rb +27 -0
  60. data/lib/evoasm/gen/translator.rb +1102 -0
  61. data/lib/evoasm/gen/version.rb +5 -0
  62. data/lib/evoasm/gen/x64/funcs.rb +495 -0
  63. data/lib/evoasm/gen/x64/inst.rb +781 -0
  64. data/lib/evoasm/gen/x64.rb +237 -0
  65. data/lib/evoasm/gen.rb +8 -0
  66. data/lib/evoasm/program.rb +23 -0
  67. data/lib/evoasm/search.rb +40 -0
  68. data/lib/evoasm/tasks/gen_task.rb +86 -0
  69. data/lib/evoasm/tasks/template_task.rb +52 -0
  70. data/lib/evoasm/version.rb +3 -0
  71. data/lib/evoasm.rb +22 -0
  72. data/test/test_helper.rb +1 -0
  73. data/test/x64/test_helper.rb +19 -0
  74. data/test/x64/x64_test.rb +87 -0
  75. metadata +221 -0
@@ -0,0 +1,5 @@
1
+ module Evoasm
2
+ module Gen
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -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