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.
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!