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
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
|
18
|
-
| ADRP Xd COMMA
|
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
|
34
|
-
| CBZ
|
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
|
137
|
-
| TBNZ
|
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
|
284
|
-
| B DOT cond
|
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
|
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
|
-
|
1052
|
-
: Xd COMMA imm COMMA
|
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
|
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;
|
data/lib/aarch64/version.rb
CHANGED
data/lib/aarch64.rb
CHANGED
@@ -287,7 +287,7 @@ class BaseInstructionsTest < AArch64::Test
|
|
287
287
|
end
|
288
288
|
|
289
289
|
# SYS #<op1>, C7, <Cm>, #<op2>, <Xt>
|
290
|
-
|
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 "
|
329
|
+
assert_one_insn "autia1716" do |asm|
|
330
330
|
asm.autia1716
|
331
331
|
end
|
332
332
|
|
333
333
|
# AUTIASP
|
334
|
-
assert_one_insn "
|
334
|
+
assert_one_insn "autiasp" do |asm|
|
335
335
|
asm.autiasp
|
336
336
|
end
|
337
337
|
|
338
338
|
# AUTIAZ
|
339
|
-
assert_one_insn "
|
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 "
|
363
|
+
assert_one_insn "autib1716" do |asm|
|
364
364
|
asm.autib1716
|
365
365
|
end
|
366
366
|
|
367
367
|
# AUTIBSP
|
368
|
-
assert_one_insn "
|
368
|
+
assert_one_insn "autibsp" do |asm|
|
369
369
|
asm.autibsp
|
370
370
|
end
|
371
371
|
|
372
372
|
# AUTIBZ
|
373
|
-
assert_one_insn "
|
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
|
715
|
-
|
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 "
|
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
|
-
|
4659
|
-
|
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
|
-
|
4668
|
-
|
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
|
-
|
4673
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
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
|
-
|
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
|
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:
|
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:
|
84
|
+
name: odinflex
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
87
|
- - "~>"
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: '1.
|
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.
|
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.
|
397
|
+
rubygems_version: 3.5.3
|
384
398
|
signing_key:
|
385
399
|
specification_version: 4
|
386
400
|
summary: Write ARM64 assembly in Ruby!
|