aarch64 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -0
- data/Rakefile +41 -1
- data/aarch64.gemspec +2 -1
- data/lib/aarch64/instructions/adrp.rb +1 -1
- data/lib/aarch64/parser.rb +407 -4
- data/lib/aarch64/parser.tab.rb +2255 -2849
- data/lib/aarch64/parser.y +23 -12
- data/lib/aarch64/version.rb +1 -1
- data/lib/aarch64.rb +1 -0
- data/test/base_instructions_test.rb +19 -19
- data/test/parser_test.rb +99 -11
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea2cf209e63aaf787b7a0a05f5d1788c3bfa36f1cee6fa1a812a99e2de5e42eb
|
4
|
+
data.tar.gz: 8d60abcae40ed475e8f3756892f432a88e99501e23f5df2d113e02b64042290f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44a6660bab9ee5db6f80b4714e8fc53d64f351f1ba2c9b2293826d83215423944fd8a2b444ea4cded815b09ed70f2bef289eb25ef5ff596dc781ceeb781a4643
|
7
|
+
data.tar.gz: b6e384d4d8743cd74a4324fb7e2e50f1f3317446a8d0ff2518ccecabed09634f8c0126e8831af21e5d57284254e3c9d5f83e578f924bc2e2d84b0f05b6e3ac4a
|
data/README.md
CHANGED
@@ -70,6 +70,32 @@ asm.movk X0, 0xF00D, lsl: 16
|
|
70
70
|
asm.ret
|
71
71
|
```
|
72
72
|
|
73
|
+
Here is another example of the same assembly, but using the built-in ARM64
|
74
|
+
assembly parser:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
require "jit_buffer"
|
78
|
+
require "aarch64/parser"
|
79
|
+
|
80
|
+
parser = AArch64::Parser.new
|
81
|
+
asm = parser.parse <<~eoasm
|
82
|
+
movz x0, 0xCAFE
|
83
|
+
movk x0, 0xF00D, lsl #16
|
84
|
+
ret
|
85
|
+
eoasm
|
86
|
+
|
87
|
+
# create a JIT buffer
|
88
|
+
jit_buffer = JITBuffer.new 4096
|
89
|
+
|
90
|
+
# Write the instructions to a JIT buffer
|
91
|
+
jit_buffer.writeable!
|
92
|
+
asm.write_to jit_buffer
|
93
|
+
jit_buffer.executable!
|
94
|
+
|
95
|
+
# Execute the JIT buffer
|
96
|
+
p jit_buffer.to_function([], -Fiddle::TYPE_INT).call.to_s(16) # => f00dcafe
|
97
|
+
```
|
98
|
+
|
73
99
|
## Hacking / Contributing
|
74
100
|
|
75
101
|
Hacking on this gem should be similar to most. Just do:
|
data/Rakefile
CHANGED
@@ -162,7 +162,7 @@ end
|
|
162
162
|
|
163
163
|
rule ".tab.rb" => [".y"] do |t|
|
164
164
|
puts "#" * 90
|
165
|
-
sh "gel exec racc -
|
165
|
+
sh "gel exec racc -v #{t.source}"
|
166
166
|
puts "#" * 90
|
167
167
|
end
|
168
168
|
|
@@ -205,3 +205,43 @@ task "autotest" do
|
|
205
205
|
end
|
206
206
|
end
|
207
207
|
end
|
208
|
+
|
209
|
+
# Make a test from the assembly in stdin.
|
210
|
+
# $ echo "brk #0x1" | rake make_test
|
211
|
+
# assert_bytes [0x20, 00, 0x20, 0xd4] do |asm|
|
212
|
+
# asm.brk #0x1
|
213
|
+
# end
|
214
|
+
task :make_test do
|
215
|
+
require "odinflex/mach-o"
|
216
|
+
require "tempfile"
|
217
|
+
|
218
|
+
begin
|
219
|
+
asm = $stdin.read
|
220
|
+
bin = Tempfile.new("bin")
|
221
|
+
source = Tempfile.new("asm")
|
222
|
+
source.puts ".global _start"
|
223
|
+
source.puts ".align 2"
|
224
|
+
source.puts "_start:"
|
225
|
+
source.puts
|
226
|
+
source.write asm
|
227
|
+
source.flush
|
228
|
+
system("as -o #{bin.path} #{source.path}")
|
229
|
+
|
230
|
+
my_macho = OdinFlex::MachO.new bin
|
231
|
+
my_macho.each do |section|
|
232
|
+
if section.section? && section.sectname == "__text"
|
233
|
+
bin.seek(section.offset, IO::SEEK_SET)
|
234
|
+
(section.size / 4).times do
|
235
|
+
bytes = bin.read(4).unpack("C4").map { |x| sprintf("%#02x", x) }.join(", ")
|
236
|
+
puts "assert_bytes [#{bytes}] do |asm|"
|
237
|
+
puts " asm.#{asm}"
|
238
|
+
puts "end"
|
239
|
+
end
|
240
|
+
#p section.start_pos
|
241
|
+
end
|
242
|
+
end
|
243
|
+
ensure
|
244
|
+
bin.unlink
|
245
|
+
source.unlink
|
246
|
+
end
|
247
|
+
end
|
data/aarch64.gemspec
CHANGED
@@ -14,9 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.homepage = "https://github.com/tenderlove/aarch64"
|
15
15
|
s.license = "Apache-2.0"
|
16
16
|
|
17
|
+
s.add_runtime_dependency 'racc', '~> 1.6'
|
17
18
|
s.add_development_dependency 'hatstone', '~> 1.0.0'
|
18
19
|
s.add_development_dependency 'jit_buffer', '~> 1.0.0'
|
19
20
|
s.add_development_dependency 'minitest', '~> 5.15'
|
20
21
|
s.add_development_dependency 'rake', '~> 13.0'
|
21
|
-
s.add_development_dependency '
|
22
|
+
s.add_development_dependency 'odinflex', '~> 1.0'
|
22
23
|
end
|
data/lib/aarch64/parser.rb
CHANGED
@@ -152,9 +152,20 @@ module AArch64
|
|
152
152
|
|
153
153
|
def parse str
|
154
154
|
str += "\n" unless str.end_with?("\n")
|
155
|
-
|
156
|
-
|
157
|
-
|
155
|
+
parse_states = [
|
156
|
+
# First pass: Label parsing
|
157
|
+
:first_pass,
|
158
|
+
# Second pass: Code generation
|
159
|
+
:second_pass
|
160
|
+
]
|
161
|
+
@labels = {}
|
162
|
+
parse_states.each do |state|
|
163
|
+
@scan = StringScanner.new str
|
164
|
+
@asm = AArch64::Assembler.new
|
165
|
+
@state = state
|
166
|
+
do_parse
|
167
|
+
end
|
168
|
+
|
158
169
|
@asm
|
159
170
|
end
|
160
171
|
|
@@ -166,12 +177,394 @@ module AArch64
|
|
166
177
|
SYS_REG_MAP = Hash[AArch64::SystemRegisters.constants.map { |k|
|
167
178
|
[k.to_s.downcase, AArch64::SystemRegisters.const_get(k)]
|
168
179
|
}]
|
180
|
+
# Created with: puts File.read('./lib/aarch64/parser.y').scan(/\b[A-Z][A-Z\d]+\b/).sort.uniq - ['LABEL', 'LABEL_CREATE']
|
181
|
+
KEYWORDS = %w[
|
182
|
+
ADC
|
183
|
+
ADCS
|
184
|
+
ADD
|
185
|
+
ADDS
|
186
|
+
ADR
|
187
|
+
ADRP
|
188
|
+
ALLE1
|
189
|
+
ALLE1IS
|
190
|
+
ALLE1OS
|
191
|
+
ALLE2
|
192
|
+
ALLE2IS
|
193
|
+
ALLE2OS
|
194
|
+
ALLE3
|
195
|
+
ALLE3IS
|
196
|
+
ALLE3OS
|
197
|
+
AND
|
198
|
+
ANDS
|
199
|
+
ASIDE1
|
200
|
+
ASIDE1IS
|
201
|
+
ASIDE1OS
|
202
|
+
ASR
|
203
|
+
AT
|
204
|
+
AUTDA
|
205
|
+
B
|
206
|
+
BANG
|
207
|
+
BFI
|
208
|
+
BFXIL
|
209
|
+
BIC
|
210
|
+
BICS
|
211
|
+
BL
|
212
|
+
BLR
|
213
|
+
BR
|
214
|
+
BRK
|
215
|
+
CBNZ
|
216
|
+
CBZ
|
217
|
+
CCMN
|
218
|
+
CCMP
|
219
|
+
CGDSW
|
220
|
+
CGDVAC
|
221
|
+
CGDVADP
|
222
|
+
CGDVAP
|
223
|
+
CGSW
|
224
|
+
CGVAC
|
225
|
+
CGVADP
|
226
|
+
CGVAP
|
227
|
+
CIGDSW
|
228
|
+
CIGDVAC
|
229
|
+
CIGSW
|
230
|
+
CIGVAC
|
231
|
+
CINC
|
232
|
+
CINV
|
233
|
+
CISW
|
234
|
+
CIVAC
|
235
|
+
CLREX
|
236
|
+
CLS
|
237
|
+
CLZ
|
238
|
+
CMN
|
239
|
+
CMP
|
240
|
+
CNEG
|
241
|
+
COMMA
|
242
|
+
CRC32B
|
243
|
+
CRC32CB
|
244
|
+
CRC32CH
|
245
|
+
CRC32CW
|
246
|
+
CRC32CX
|
247
|
+
CRC32H
|
248
|
+
CRC32W
|
249
|
+
CRC32X
|
250
|
+
CSEL
|
251
|
+
CSET
|
252
|
+
CSETM
|
253
|
+
CSINC
|
254
|
+
CSINV
|
255
|
+
CSNEG
|
256
|
+
CSW
|
257
|
+
CVAC
|
258
|
+
CVADP
|
259
|
+
CVAP
|
260
|
+
CVAU
|
261
|
+
DC
|
262
|
+
DCPS1
|
263
|
+
DCPS2
|
264
|
+
DCPS3
|
265
|
+
DMB
|
266
|
+
DOT
|
267
|
+
DRPS
|
268
|
+
DSB
|
269
|
+
EOL
|
270
|
+
EON
|
271
|
+
EOR
|
272
|
+
EQ
|
273
|
+
ERET
|
274
|
+
EXTR
|
275
|
+
GE
|
276
|
+
GT
|
277
|
+
GVA
|
278
|
+
GZVA
|
279
|
+
HI
|
280
|
+
HINT
|
281
|
+
HLT
|
282
|
+
HS
|
283
|
+
HVC
|
284
|
+
IALLU
|
285
|
+
IALLUIS
|
286
|
+
IC
|
287
|
+
IGDSW
|
288
|
+
IGDVAC
|
289
|
+
IGSW
|
290
|
+
IGVAC
|
291
|
+
IPAS2E1
|
292
|
+
IPAS2E1IS
|
293
|
+
IPAS2E1OS
|
294
|
+
IPAS2LE1
|
295
|
+
IPAS2LE1IS
|
296
|
+
IPAS2LE1OS
|
297
|
+
ISB
|
298
|
+
ISH
|
299
|
+
ISHLD
|
300
|
+
ISHST
|
301
|
+
ISW
|
302
|
+
IVAC
|
303
|
+
IVAU
|
304
|
+
LD
|
305
|
+
LDAR
|
306
|
+
LDARB
|
307
|
+
LDARH
|
308
|
+
LDAXP
|
309
|
+
LDAXR
|
310
|
+
LDAXRB
|
311
|
+
LDAXRH
|
312
|
+
LDNP
|
313
|
+
LDP
|
314
|
+
LDPSW
|
315
|
+
LDR
|
316
|
+
LDRB
|
317
|
+
LDRH
|
318
|
+
LDRSB
|
319
|
+
LDRSH
|
320
|
+
LDRSW
|
321
|
+
LDTR
|
322
|
+
LDTRB
|
323
|
+
LDTRH
|
324
|
+
LDTRSB
|
325
|
+
LDTRSH
|
326
|
+
LDTRSW
|
327
|
+
LDUR
|
328
|
+
LDURB
|
329
|
+
LDURH
|
330
|
+
LDURSB
|
331
|
+
LDURSH
|
332
|
+
LDURSW
|
333
|
+
LDXP
|
334
|
+
LDXR
|
335
|
+
LDXRB
|
336
|
+
LDXRH
|
337
|
+
LE
|
338
|
+
LO
|
339
|
+
LS
|
340
|
+
LSL
|
341
|
+
LSQ
|
342
|
+
LSR
|
343
|
+
LT
|
344
|
+
MADD
|
345
|
+
MI
|
346
|
+
MNEG
|
347
|
+
MOV
|
348
|
+
MOVK
|
349
|
+
MOVN
|
350
|
+
MOVZ
|
351
|
+
MRS
|
352
|
+
MSR
|
353
|
+
MSUB
|
354
|
+
MUL
|
355
|
+
MVN
|
356
|
+
NE
|
357
|
+
NEG
|
358
|
+
NEGS
|
359
|
+
NGC
|
360
|
+
NGCS
|
361
|
+
NOP
|
362
|
+
NSH
|
363
|
+
NSHLD
|
364
|
+
NSHST
|
365
|
+
NUMBER
|
366
|
+
ORN
|
367
|
+
ORR
|
368
|
+
OSH
|
369
|
+
OSHLD
|
370
|
+
OSHST
|
371
|
+
PL
|
372
|
+
PRFM
|
373
|
+
PRFOP
|
374
|
+
PRFUM
|
375
|
+
PSSBB
|
376
|
+
RBIT
|
377
|
+
RET
|
378
|
+
REV
|
379
|
+
REV16
|
380
|
+
REV32
|
381
|
+
RIPAS2E1
|
382
|
+
RIPAS2E1IS
|
383
|
+
RIPAS2E1OS
|
384
|
+
RIPAS2LE1
|
385
|
+
RIPAS2LE1IS
|
386
|
+
RIPAS2LE1OS
|
387
|
+
ROR
|
388
|
+
RSQ
|
389
|
+
RVAAE1
|
390
|
+
RVAAE1IS
|
391
|
+
RVAAE1OS
|
392
|
+
RVAALE1
|
393
|
+
RVAALE1IS
|
394
|
+
RVAALE1OS
|
395
|
+
RVAE1
|
396
|
+
RVAE1IS
|
397
|
+
RVAE1OS
|
398
|
+
RVAE2
|
399
|
+
RVAE2IS
|
400
|
+
RVAE2OS
|
401
|
+
RVAE3
|
402
|
+
RVAE3IS
|
403
|
+
RVAE3OS
|
404
|
+
RVALE1
|
405
|
+
RVALE1IS
|
406
|
+
RVALE1OS
|
407
|
+
RVALE2
|
408
|
+
RVALE2IS
|
409
|
+
RVALE2OS
|
410
|
+
RVALE3
|
411
|
+
RVALE3IS
|
412
|
+
RVALE3OS
|
413
|
+
S12E0R
|
414
|
+
S12E0W
|
415
|
+
S12E1R
|
416
|
+
S12E1W
|
417
|
+
S1E0R
|
418
|
+
S1E0W
|
419
|
+
S1E1R
|
420
|
+
S1E1RP
|
421
|
+
S1E1W
|
422
|
+
S1E1WP
|
423
|
+
S1E2R
|
424
|
+
S1E2W
|
425
|
+
S1E3R
|
426
|
+
S1E3W
|
427
|
+
SBC
|
428
|
+
SBCS
|
429
|
+
SBFIZ
|
430
|
+
SBFX
|
431
|
+
SDIV
|
432
|
+
SEV
|
433
|
+
SEVL
|
434
|
+
SMADDL
|
435
|
+
SMC
|
436
|
+
SMNEGL
|
437
|
+
SMSUBL
|
438
|
+
SMULH
|
439
|
+
SMULL
|
440
|
+
SP
|
441
|
+
SSBB
|
442
|
+
ST
|
443
|
+
STLR
|
444
|
+
STLRB
|
445
|
+
STLRH
|
446
|
+
STLXP
|
447
|
+
STLXR
|
448
|
+
STLXRB
|
449
|
+
STLXRH
|
450
|
+
STNP
|
451
|
+
STP
|
452
|
+
STR
|
453
|
+
STRB
|
454
|
+
STRH
|
455
|
+
STTR
|
456
|
+
STTRB
|
457
|
+
STTRH
|
458
|
+
STUR
|
459
|
+
STURB
|
460
|
+
STURH
|
461
|
+
STXP
|
462
|
+
STXR
|
463
|
+
STXRB
|
464
|
+
STXRH
|
465
|
+
SUB
|
466
|
+
SUBS
|
467
|
+
SVC
|
468
|
+
SXTB
|
469
|
+
SXTH
|
470
|
+
SXTW
|
471
|
+
SXTX
|
472
|
+
SY
|
473
|
+
SYS
|
474
|
+
SYSL
|
475
|
+
SYSTEMREG
|
476
|
+
TBNZ
|
477
|
+
TBZ
|
478
|
+
TLBI
|
479
|
+
TST
|
480
|
+
UBFIZ
|
481
|
+
UBFX
|
482
|
+
UDIV
|
483
|
+
UMADDL
|
484
|
+
UMNEGL
|
485
|
+
UMSUBL
|
486
|
+
UMULH
|
487
|
+
UMULL
|
488
|
+
UXTB
|
489
|
+
UXTH
|
490
|
+
UXTW
|
491
|
+
UXTX
|
492
|
+
VAAE1
|
493
|
+
VAAE1IS
|
494
|
+
VAAE1OS
|
495
|
+
VAALE1
|
496
|
+
VAALE1IS
|
497
|
+
VAALE1OS
|
498
|
+
VAE1
|
499
|
+
VAE1IS
|
500
|
+
VAE1OS
|
501
|
+
VAE2
|
502
|
+
VAE2IS
|
503
|
+
VAE2OS
|
504
|
+
VAE3
|
505
|
+
VAE3IS
|
506
|
+
VAE3OS
|
507
|
+
VALE1
|
508
|
+
VALE1IS
|
509
|
+
VALE1OS
|
510
|
+
VALE2
|
511
|
+
VALE2IS
|
512
|
+
VALE2OS
|
513
|
+
VALE3
|
514
|
+
VALE3IS
|
515
|
+
VALE3OS
|
516
|
+
VC
|
517
|
+
VMALLE1
|
518
|
+
VMALLE1IS
|
519
|
+
VMALLE1OS
|
520
|
+
VMALLS12E1
|
521
|
+
VMALLS12E1IS
|
522
|
+
VMALLS12E1OS
|
523
|
+
VS
|
524
|
+
WFE
|
525
|
+
WFI
|
526
|
+
WSP
|
527
|
+
XZR
|
528
|
+
YIELD
|
529
|
+
ZVA
|
530
|
+
].freeze
|
531
|
+
KEYWORDS_SCAN = /(#{Regexp.union(KEYWORDS.sort).source})\b/i
|
532
|
+
LABEL_SCAN = /[a-zA-Z_]\w+/
|
533
|
+
LABEL_CREATE_SCAN = /#{LABEL_SCAN}:/
|
534
|
+
|
535
|
+
def register_label str
|
536
|
+
return unless @state == :first_pass
|
537
|
+
|
538
|
+
if @labels.include?(str)
|
539
|
+
raise "symbol '#{str}' is already defined"
|
540
|
+
end
|
541
|
+
|
542
|
+
label = @asm.make_label(str)
|
543
|
+
@asm.put_label(label)
|
544
|
+
@labels[str] = label
|
545
|
+
|
546
|
+
nil
|
547
|
+
end
|
548
|
+
|
549
|
+
def label_for str
|
550
|
+
# In the first pass, all valid labels are not known yet i.e. forward references
|
551
|
+
# Return a placeholder value instead.
|
552
|
+
if @state == :first_pass
|
553
|
+
@asm.make_label(str)
|
554
|
+
else
|
555
|
+
raise("Label #{str.inspect} not defined") unless @labels.key?(str)
|
556
|
+
@labels[str]
|
557
|
+
end
|
558
|
+
end
|
169
559
|
|
170
560
|
def _next_token
|
171
561
|
return _next_token if @scan.scan(/[\t ]+/) # skip whitespace
|
562
|
+
return if @scan.eos?
|
172
563
|
|
173
564
|
if str = @scan.scan(/\n/)
|
174
565
|
return [:EOL, :EOL]
|
566
|
+
elsif str = @scan.scan(LABEL_CREATE_SCAN)
|
567
|
+
[:LABEL_CREATE, str[0...-1]]
|
175
568
|
elsif str = @scan.scan(/x\d+/i)
|
176
569
|
[:Xd, AArch64::Registers.const_get(str.upcase)]
|
177
570
|
elsif str = @scan.scan(/w\d+/i)
|
@@ -218,10 +611,20 @@ module AArch64
|
|
218
611
|
end
|
219
612
|
elsif str = @scan.scan(SYS_REG_SCAN)
|
220
613
|
[:SYSTEMREG, SYS_REG_MAP[str.downcase]]
|
221
|
-
elsif str = @scan.scan(
|
614
|
+
elsif str = @scan.scan(KEYWORDS_SCAN)
|
222
615
|
[str.upcase.to_sym, str]
|
616
|
+
elsif str = @scan.scan(LABEL_SCAN)
|
617
|
+
[:LABEL, str]
|
223
618
|
else
|
619
|
+
[:UNKNOWN_CHAR, @scan.getch]
|
224
620
|
end
|
225
621
|
end
|
622
|
+
|
623
|
+
def on_error(token_id, val, vstack)
|
624
|
+
token_str = token_to_str(token_id) || '?'
|
625
|
+
string = @scan.string
|
626
|
+
line_number = string.byteslice(0, @scan.pos).count("\n") + 1
|
627
|
+
raise ParseError, "parse error on value #{val.inspect} (#{token_str}) on line #{line_number} at pos #{@scan.pos}/#{string.bytesize}"
|
628
|
+
end
|
226
629
|
end
|
227
630
|
end
|