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