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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4148547f29912a9cea29d06ba88ebafff8ffd701b187ab9aa3a0b4ee1d309b0
4
- data.tar.gz: dc7b08ee7be2e57acfb2d5181d374a9baf6806be65dee0318cd95417349a2cfc
3
+ metadata.gz: ea2cf209e63aaf787b7a0a05f5d1788c3bfa36f1cee6fa1a812a99e2de5e42eb
4
+ data.tar.gz: 8d60abcae40ed475e8f3756892f432a88e99501e23f5df2d113e02b64042290f
5
5
  SHA512:
6
- metadata.gz: f215a62f40c5ad36e81ec7d1d1110e21639ab0b19950283f4b5dbde46e5b26c17081a527d41dca600c4a8e8aa07eb0fc5f1f21a68d4425084c5eaf94de8baaef
7
- data.tar.gz: 4d0027eeb4a45b5d77e409b2fc343d59ec19548b4874f1c2e61bfeabcecb991ee2527a0969133f1029aa13e2623361bef3e6637ed65f9617001f5709ab31b99a
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 -E -v #{t.source}"
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 'racc', '~> 1.6'
22
+ s.add_development_dependency 'odinflex', '~> 1.0'
22
23
  end
@@ -10,7 +10,7 @@ module AArch64
10
10
  end
11
11
 
12
12
  def encode _
13
- label = @label / 4096
13
+ label = unwrap_label(@label, 0) / 4096
14
14
  ADRP(label & 0x3, check_mask(label >> 2, 0x7ffff), @xd)
15
15
  end
16
16
 
@@ -152,9 +152,20 @@ module AArch64
152
152
 
153
153
  def parse str
154
154
  str += "\n" unless str.end_with?("\n")
155
- @scan = StringScanner.new str
156
- @asm = AArch64::Assembler.new
157
- do_parse
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(/\w+/)
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