aarch64 2.0.2 → 2.1.0
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 +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
|