aarch64 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/aarch64/parser.y CHANGED
@@ -14,8 +14,8 @@ rule
14
14
  | adcs
15
15
  | ADD add_body { val[1].apply(@asm, val[0]) }
16
16
  | ADDS add_body { val[1].apply(@asm, val[0]) }
17
- | ADR Xd COMMA imm { @asm.adr(val[1], val[3]) }
18
- | ADRP Xd COMMA imm { @asm.adrp(val[1], val[3]) }
17
+ | ADR Xd COMMA imm_or_label { @asm.adr(val[1], val[3]) }
18
+ | ADRP Xd COMMA imm_or_label { @asm.adrp(val[1], val[3]) }
19
19
  | AND and_body { val[1].apply(@asm, val[0]) }
20
20
  | ANDS and_body { val[1].apply(@asm, val[0]) }
21
21
  | asr { val[0].apply(@asm, :asr) }
@@ -30,8 +30,8 @@ rule
30
30
  | blr
31
31
  | br
32
32
  | BRK imm { @asm.brk(val[1]) }
33
- | CBNZ reg_imm { val[1].apply(@asm, val[0]) }
34
- | CBZ reg_imm { val[1].apply(@asm, val[0]) }
33
+ | CBNZ reg_imm_or_label { val[1].apply(@asm, val[0]) }
34
+ | CBZ reg_imm_or_label { val[1].apply(@asm, val[0]) }
35
35
  | cinc
36
36
  | cinv
37
37
  | clrex
@@ -133,8 +133,8 @@ rule
133
133
  | SXTW xd_wd { val[1].apply(@asm, :sxtw) }
134
134
  | sys
135
135
  | sysl
136
- | TBZ reg_imm_imm { val[1].apply(@asm, val[0]) }
137
- | TBNZ reg_imm_imm { val[1].apply(@asm, val[0]) }
136
+ | TBZ reg_imm_imm_or_label { val[1].apply(@asm, val[0]) }
137
+ | TBNZ reg_imm_imm_or_label { val[1].apply(@asm, val[0]) }
138
138
  | tlbi
139
139
  | tst
140
140
  | UBFIZ ubfiz_body { val[1].apply(@asm, val[0]) }
@@ -150,6 +150,7 @@ rule
150
150
  | WFE { @asm.wfe }
151
151
  | WFI { @asm.wfi }
152
152
  | YIELD { @asm.yield }
153
+ | LABEL_CREATE { register_label(val[0]) }
153
154
  ;
154
155
 
155
156
  adc
@@ -280,8 +281,8 @@ rule
280
281
  at: AT at_op COMMA Xd { @asm.at(val[1].to_sym, val[3]) };
281
282
 
282
283
  b
283
- : B imm { @asm.b(val[1]) }
284
- | B DOT cond imm { @asm.b(val[3], cond: val[2]) }
284
+ : B imm_or_label { @asm.b(val[1]) }
285
+ | B DOT cond imm_or_label { @asm.b(val[3], cond: val[2]) }
285
286
  ;
286
287
 
287
288
  bfi
@@ -313,7 +314,7 @@ rule
313
314
  | AUTDA Xd COMMA SP { @asm.autda(val[1], val[3]) }
314
315
  ;
315
316
 
316
- bl : BL imm { @asm.bl(val[1]) } ;
317
+ bl : BL imm_or_label { @asm.bl(val[1]) } ;
317
318
  blr : BLR Xd { @asm.blr(val[1]) } ;
318
319
  br : BR Xd { @asm.br(val[1]) } ;
319
320
 
@@ -1048,11 +1049,11 @@ rule
1048
1049
  }
1049
1050
  ;
1050
1051
 
1051
- reg_imm_imm
1052
- : Xd COMMA imm COMMA imm {
1052
+ reg_imm_imm_or_label
1053
+ : Xd COMMA imm COMMA imm_or_label {
1053
1054
  result = ThreeArg.new(val[0], val[2], val[4])
1054
1055
  }
1055
- | Wd COMMA imm COMMA imm {
1056
+ | Wd COMMA imm COMMA imm_or_label {
1056
1057
  result = ThreeArg.new(val[0], val[2], val[4])
1057
1058
  }
1058
1059
  ;
@@ -1194,6 +1195,11 @@ rule
1194
1195
  | Xd COMMA imm { result = TwoArg.new(val[0], val[2]) }
1195
1196
  ;
1196
1197
 
1198
+ reg_imm_or_label
1199
+ : Wd COMMA imm_or_label { result = TwoArg.new(val[0], val[2]) }
1200
+ | Xd COMMA imm_or_label { result = TwoArg.new(val[0], val[2]) }
1201
+ ;
1202
+
1197
1203
  reg_reg_imm
1198
1204
  : Wd COMMA Wd COMMA imm {
1199
1205
  result = ThreeArg.new(val[0], val[2], val[4])
@@ -1232,6 +1238,11 @@ rule
1232
1238
  | NUMBER { result = val[0] }
1233
1239
  ;
1234
1240
 
1241
+ imm_or_label
1242
+ : LABEL { result = label_for(val[0]) }
1243
+ | imm
1244
+ ;
1245
+
1235
1246
  xt: Xd | XZR;
1236
1247
 
1237
1248
  cond : EQ | LO | LT | HS | GT | LE | NE | MI | GE | PL | LS | HI | VC | VS;
@@ -1,3 +1,3 @@
1
1
  module AArch64
2
- VERSION = "2.0.2"
2
+ VERSION = "2.1.0"
3
3
  end
data/lib/aarch64.rb CHANGED
@@ -288,6 +288,7 @@ module AArch64
288
288
  end
289
289
 
290
290
  def adrp xd, label
291
+ label = Immediate.new(label) if label.integer?
291
292
  a ADRP.new(xd, label)
292
293
  end
293
294
 
@@ -287,7 +287,7 @@ class BaseInstructionsTest < AArch64::Test
287
287
  end
288
288
 
289
289
  # SYS #<op1>, C7, <Cm>, #<op2>, <Xt>
290
- assert_one_insn "sys #0, c7, c9, #0, x1" do |asm|
290
+ assert_bytes [0x1, 0x79, 0x8, 0xd5] do |asm|
291
291
  asm.at :s1e1rp, X1
292
292
  end
293
293
  end
@@ -326,17 +326,17 @@ class BaseInstructionsTest < AArch64::Test
326
326
  asm.autiza X1
327
327
  end
328
328
  # AUTIA1716
329
- assert_one_insn "hint #0xc" do |asm|
329
+ assert_one_insn "autia1716" do |asm|
330
330
  asm.autia1716
331
331
  end
332
332
 
333
333
  # AUTIASP
334
- assert_one_insn "hint #0x1d" do |asm|
334
+ assert_one_insn "autiasp" do |asm|
335
335
  asm.autiasp
336
336
  end
337
337
 
338
338
  # AUTIAZ
339
- assert_one_insn "hint #0x1c" do |asm|
339
+ assert_one_insn "autiaz" do |asm|
340
340
  asm.autiaz
341
341
  end
342
342
  end
@@ -360,17 +360,17 @@ class BaseInstructionsTest < AArch64::Test
360
360
  end
361
361
 
362
362
  # AUTIB1716
363
- assert_one_insn "hint #0xe" do |asm|
363
+ assert_one_insn "autib1716" do |asm|
364
364
  asm.autib1716
365
365
  end
366
366
 
367
367
  # AUTIBSP
368
- assert_one_insn "hint #0x1f" do |asm|
368
+ assert_one_insn "autibsp" do |asm|
369
369
  asm.autibsp
370
370
  end
371
371
 
372
372
  # AUTIBZ
373
- assert_one_insn "hint #0x1e" do |asm|
373
+ assert_one_insn "autibz" do |asm|
374
374
  asm.autibz
375
375
  end
376
376
  end
@@ -711,13 +711,14 @@ class BaseInstructionsTest < AArch64::Test
711
711
 
712
712
  def test_BRK
713
713
  # BRK #<imm>
714
- asm.brk 1
715
- assert_one_insn "brk #0x1"
714
+ assert_bytes [0x20, 00, 0x20, 0xd4] do |asm|
715
+ asm.brk 0x1
716
+ end
716
717
  end
717
718
 
718
719
  def test_BTI
719
720
  # BTI {<targets>}
720
- assert_one_insn "hint #0x20" do |asm|
721
+ assert_one_insn "bti" do |asm|
721
722
  asm.bti :c
722
723
  end
723
724
  end
@@ -4655,22 +4656,21 @@ class BaseInstructionsTest < AArch64::Test
4655
4656
  end
4656
4657
 
4657
4658
  def test_MOVZ
4658
- asm.movz X0, 0x2a
4659
- assert_one_insn "movz x0, #0x2a"
4660
- # MOVZ
4661
- assert_bytes [0x02,0x00,0xa0,0x52] do |asm|
4662
- asm.movz w2, 0, lsl(16)
4659
+ assert_bytes [0x40, 0x5, 0x80, 0xd2] do |asm|
4660
+ asm.movz X0, 0x2a
4663
4661
  end
4664
4662
  end
4665
4663
 
4666
4664
  def test_movz_shift
4667
- asm.movz X0, 0x2a, lsl: 16
4668
- assert_one_insn "movz x0, #0x2a, lsl #16"
4665
+ assert_bytes [0x40, 0x5, 0xa0, 0xd2] do |asm|
4666
+ asm.movz X0, 0x2a, lsl: 16
4667
+ end
4669
4668
  end
4670
4669
 
4671
4670
  def test_movz_with_w
4672
- asm.movz W0, 0x2a
4673
- assert_one_insn "movz w0, #0x2a"
4671
+ assert_bytes [0x40, 0x5, 0x80, 82] do |asm|
4672
+ asm.movz W0, 0x2a
4673
+ end
4674
4674
  end
4675
4675
 
4676
4676
  def test_MRS
data/test/parser_test.rb CHANGED
@@ -2,12 +2,20 @@ require "helper"
2
2
  require "aarch64/parser"
3
3
 
4
4
  class ParserTest < AArch64::Test
5
+
6
+ def test_parse_error
7
+ error = assert_raises(Racc::ParseError) do
8
+ parse "mov x1, x0\nmov x1, #2 // comments not supported"
9
+ end
10
+ assert_equal 'parse error on value "/" (error) on line 2 at pos 23/48', error.message
11
+ end
12
+
5
13
  def test_parse
6
- assert_round_trip "movz x0, 0xCAFE", output: ["movz x0, #0xcafe"]
7
- assert_round_trip "movz x0, #0xcafe"
8
- assert_round_trip "movz x0, #0xcafe, lsl #16"
9
- assert_round_trip "movz w0, #0xcafe"
10
- assert_round_trip "movz w0, #0xcafe, lsl #16"
14
+ assert_bytes "movz x0, 0xCAFE", [0xc0, 0x5f, 0x99, 0xd2]
15
+ assert_bytes "movz x0, #0xcafe", [0xc0, 0x5f, 0x99, 0xd2]
16
+ assert_bytes "movz x0, #0xcafe, lsl #16", [0xc0, 0x5f, 0xb9, 0xd2]
17
+ assert_bytes "movz w0, #0xcafe", [0xc0, 0x5f, 0x99, 0x52]
18
+ assert_bytes "movz w0, #0xcafe, lsl #16", [0xc0, 0x5f, 0xb9, 0x52]
11
19
  end
12
20
 
13
21
  def test_autda
@@ -16,16 +24,20 @@ class ParserTest < AArch64::Test
16
24
  assert_bytes "autda x1, x2", [0x41, 0x18, 0xc1, 0xda]
17
25
  end
18
26
 
19
- def assert_bytes input, bytes
27
+ def parse input
20
28
  parser = AArch64::Parser.new
21
29
  begin
22
30
  asm = parser.parse input
23
31
  rescue Racc::ParseError
24
- puts input
25
32
  raise
26
33
  end
27
34
  io = StringIO.new
28
35
  asm.write_to io
36
+ io
37
+ end
38
+
39
+ def assert_bytes input, bytes
40
+ io = parse input
29
41
  assert_equal bytes, io.string.bytes, ->() {
30
42
  pos = 32.times.map { |i| (i % 0x10).to_s(16) }.join.reverse
31
43
  actual_bin = sprintf("%032b", io.string.unpack1("L<"))
@@ -42,10 +54,7 @@ class ParserTest < AArch64::Test
42
54
  end
43
55
 
44
56
  def assert_round_trip input, output: [input]
45
- parser = AArch64::Parser.new
46
- asm = parser.parse input
47
- io = StringIO.new
48
- asm.write_to io
57
+ io = parse input
49
58
  assert_equal output, disasm(io.string).map { |x|
50
59
  "#{x.mnemonic} #{x.op_str}"
51
60
  }
@@ -58,6 +67,85 @@ class ParserTest < AArch64::Test
58
67
  assert_bytes "add x8, x10, #1", [0x48, 0x5, 00, 0x91]
59
68
  end
60
69
 
70
+ def test_labels_already_defined
71
+ error = assert_raises(RuntimeError) do
72
+ parse "start:\nstart:\n"
73
+ end
74
+ assert_equal "symbol 'start' is already defined", error.message
75
+ end
76
+
77
+ def test_labels_empty
78
+ assert_bytes "start:\n", []
79
+ assert_bytes <<~ASM, []
80
+ start:
81
+ end:
82
+ ASM
83
+ end
84
+
85
+ def test_labels_not_defined
86
+ examples = [
87
+ "b label",
88
+ "b.eq label",
89
+ "b.lo label",
90
+ "b.lt label",
91
+ "b.hs label",
92
+ "b.gt label",
93
+ "b.le label",
94
+ "b.ne label",
95
+ "b.mi label",
96
+ "b.ge label",
97
+ "b.pl label",
98
+ "b.ls label",
99
+ "b.hi label",
100
+ "b.vc label",
101
+ "b.vs label",
102
+ "cbz x0, label",
103
+ "cbz w0, label",
104
+ "cbnz w0, label",
105
+ "cbnz x0, label",
106
+ "tbz w1, #1, label",
107
+ "tbz x1, #1, label",
108
+ "tbnz w1, #1, label",
109
+ "tbnz x1, #1, label",
110
+ "bl label",
111
+ ]
112
+ examples.each do |instruction|
113
+ error = assert_raises(RuntimeError) do
114
+ parse instruction
115
+ end
116
+ assert_match 'Label "label" not defined', error.message
117
+ end
118
+ end
119
+
120
+ def test_labels_branch
121
+ assert_bytes <<~ASM, [0x00, 0x04, 0x00, 0x91, 0xff, 0xff, 0xff, 0x17]
122
+ loop:
123
+ add x0, x0, #1
124
+ b loop
125
+ ASM
126
+ assert_bytes <<~ASM, [0x20, 0x00, 0x80, 0xd2, 0xe0, 0xff, 0xff, 0x10]
127
+ label:
128
+ mov x0, #1
129
+ adr x0, label
130
+ ASM
131
+ end
132
+
133
+ def test_labels_forward_reference
134
+ assert_bytes "b label\nlabel:", [0x01, 0x00, 0x00, 0x14]
135
+ assert_bytes "b.eq label\nlabel:", [0x20, 0x00, 0x00, 0x54]
136
+ assert_bytes "cbz w1, label\nlabel:", [0x21, 0x00, 0x00, 0x34]
137
+ assert_bytes "cbz x1, label\nlabel:", [0x21, 0x00, 0x00, 0xb4]
138
+ assert_bytes "cbnz w1, label\nlabel:", [0x21, 0x00, 0x00, 0x35]
139
+ assert_bytes "cbnz x1, label\nlabel:", [0x21, 0x00, 0x00, 0xb5]
140
+ assert_bytes "tbz w1, #1, label\nlabel:", [0x21, 0x00, 0x08, 0x36]
141
+ assert_bytes "tbz x1, #1, label\nlabel:", [0x21, 0x00, 0x08, 0x36]
142
+ assert_bytes "tbnz w1, #1, label\nlabel:", [0x21, 0x00, 0x08, 0x37]
143
+ assert_bytes "tbnz x1, #1, label\nlabel:", [0x21, 0x00, 0x08, 0x37]
144
+ assert_bytes "bl label\nlabel:", [0x01, 0x00, 0x00, 0x94]
145
+ assert_bytes "adr x0, label\nlabel:", [0x20, 0x00, 0x00, 0x10]
146
+ assert_bytes "adrp x0, label\nlabel:", [0x00, 0x00, 0x00, 0x90]
147
+ end
148
+
61
149
  def test_bls
62
150
  assert_bytes "b.ls #0x10", [0x89, 0x00, 0000, 0x54]
63
151
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aarch64
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Patterson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-07 00:00:00.000000000 Z
11
+ date: 2024-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: racc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: hatstone
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -67,19 +81,19 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '13.0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: racc
84
+ name: odinflex
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '1.6'
89
+ version: '1.0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '1.6'
96
+ version: '1.0'
83
97
  description: Tired of writing Ruby in Ruby? Now you can write ARM64 assembly in Ruby!
84
98
  email: tenderlove@ruby-lang.org
85
99
  executables: []
@@ -380,7 +394,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
380
394
  - !ruby/object:Gem::Version
381
395
  version: '0'
382
396
  requirements: []
383
- rubygems_version: 3.5.0.dev
397
+ rubygems_version: 3.5.3
384
398
  signing_key:
385
399
  specification_version: 4
386
400
  summary: Write ARM64 assembly in Ruby!