aboutsummaryrefslogtreecommitdiff
path: root/src/jit/dis_arm64.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/dis_arm64.lua')
-rw-r--r--src/jit/dis_arm64.lua1215
1 files changed, 1215 insertions, 0 deletions
diff --git a/src/jit/dis_arm64.lua b/src/jit/dis_arm64.lua
new file mode 100644
index 00000000..909b33bc
--- /dev/null
+++ b/src/jit/dis_arm64.lua
@@ -0,0 +1,1215 @@
1----------------------------------------------------------------------------
2-- LuaJIT ARM64 disassembler module.
3--
4-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
5-- Released under the MIT license. See Copyright Notice in luajit.h
6--
7-- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
8-- Sponsored by Cisco Systems, Inc.
9----------------------------------------------------------------------------
10-- This is a helper module used by the LuaJIT machine code dumper module.
11--
12-- It disassembles most user-mode AArch64 instructions.
13-- NYI: Advanced SIMD and VFP instructions.
14------------------------------------------------------------------------------
15
16local type, tonumber = type, tonumber
17local sub, byte, format = string.sub, string.byte, string.format
18local match, gmatch, gsub = string.match, string.gmatch, string.gsub
19local rep = string.rep
20local concat = table.concat
21local bit = require("bit")
22local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex
23local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
24local ror = bit.ror
25
26------------------------------------------------------------------------------
27-- Opcode maps
28------------------------------------------------------------------------------
29
30local map_adr = { -- PC-relative addressing.
31 shift = 31, mask = 1,
32 [0] = "adrDBx", "adrpDBx"
33}
34
35local map_addsubi = { -- Add/subtract immediate.
36 shift = 29, mask = 3,
37 [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg",
38}
39
40local map_logi = { -- Logical immediate.
41 shift = 31, mask = 1,
42 [0] = {
43 shift = 22, mask = 1,
44 [0] = {
45 shift = 29, mask = 3,
46 [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
47 },
48 false -- unallocated
49 },
50 {
51 shift = 29, mask = 3,
52 [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
53 }
54}
55
56local map_movwi = { -- Move wide immediate.
57 shift = 31, mask = 1,
58 [0] = {
59 shift = 22, mask = 1,
60 [0] = {
61 shift = 29, mask = 3,
62 [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
63 }, false -- unallocated
64 },
65 {
66 shift = 29, mask = 3,
67 [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
68 },
69}
70
71local map_bitf = { -- Bitfield.
72 shift = 31, mask = 1,
73 [0] = {
74 shift = 22, mask = 1,
75 [0] = {
76 shift = 29, mask = 3,
77 [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w",
78 "bfm|bfi|bfxilDN13w",
79 "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w"
80 }
81 },
82 {
83 shift = 22, mask = 1,
84 {
85 shift = 29, mask = 3,
86 [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x",
87 "bfm|bfi|bfxilDN13x",
88 "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x"
89 }
90 }
91}
92
93local map_datai = { -- Data processing - immediate.
94 shift = 23, mask = 7,
95 [0] = map_adr, map_adr, map_addsubi, false,
96 map_logi, map_movwi, map_bitf,
97 {
98 shift = 15, mask = 0x1c0c1,
99 [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x",
100 [0x10081] = "extr|rorDNM4x"
101 }
102}
103
104local map_logsr = { -- Logical, shifted register.
105 shift = 31, mask = 1,
106 [0] = {
107 shift = 15, mask = 1,
108 [0] = {
109 shift = 29, mask = 3,
110 [0] = {
111 shift = 21, mask = 7,
112 [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
113 "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
114 },
115 {
116 shift = 21, mask = 7,
117 [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
118 "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
119 },
120 {
121 shift = 21, mask = 7,
122 [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
123 "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
124 },
125 {
126 shift = 21, mask = 7,
127 [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
128 "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
129 }
130 },
131 false -- unallocated
132 },
133 {
134 shift = 29, mask = 3,
135 [0] = {
136 shift = 21, mask = 7,
137 [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg",
138 "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg"
139 },
140 {
141 shift = 21, mask = 7,
142 [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg",
143 "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg"
144 },
145 {
146 shift = 21, mask = 7,
147 [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg",
148 "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg"
149 },
150 {
151 shift = 21, mask = 7,
152 [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg",
153 "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg"
154 }
155 }
156}
157
158local map_assh = {
159 shift = 31, mask = 1,
160 [0] = {
161 shift = 15, mask = 1,
162 [0] = {
163 shift = 29, mask = 3,
164 [0] = {
165 shift = 22, mask = 3,
166 [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
167 },
168 {
169 shift = 22, mask = 3,
170 [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg",
171 "adds|cmnD0NMSg", "adds|cmnD0NMg"
172 },
173 {
174 shift = 22, mask = 3,
175 [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
176 },
177 {
178 shift = 22, mask = 3,
179 [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
180 "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
181 },
182 },
183 false -- unallocated
184 },
185 {
186 shift = 29, mask = 3,
187 [0] = {
188 shift = 22, mask = 3,
189 [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
190 },
191 {
192 shift = 22, mask = 3,
193 [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg",
194 "adds|cmnD0NMg"
195 },
196 {
197 shift = 22, mask = 3,
198 [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
199 },
200 {
201 shift = 22, mask = 3,
202 [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
203 "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
204 }
205 }
206}
207
208local map_addsubsh = { -- Add/subtract, shifted register.
209 shift = 22, mask = 3,
210 [0] = map_assh, map_assh, map_assh
211}
212
213local map_addsubex = { -- Add/subtract, extended register.
214 shift = 22, mask = 3,
215 [0] = {
216 shift = 29, mask = 3,
217 [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg",
218 }
219}
220
221local map_addsubc = { -- Add/subtract, with carry.
222 shift = 10, mask = 63,
223 [0] = {
224 shift = 29, mask = 3,
225 [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg",
226 }
227}
228
229local map_ccomp = {
230 shift = 4, mask = 1,
231 [0] = {
232 shift = 10, mask = 3,
233 [0] = { -- Conditional compare register.
234 shift = 29, mask = 3,
235 "ccmnNMVCg", false, "ccmpNMVCg",
236 },
237 [2] = { -- Conditional compare immediate.
238 shift = 29, mask = 3,
239 "ccmnN5VCg", false, "ccmpN5VCg",
240 }
241 }
242}
243
244local map_csel = { -- Conditional select.
245 shift = 11, mask = 1,
246 [0] = {
247 shift = 10, mask = 1,
248 [0] = {
249 shift = 29, mask = 3,
250 [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false,
251 },
252 {
253 shift = 29, mask = 3,
254 [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false,
255 }
256 }
257}
258
259local map_data1s = { -- Data processing, 1 source.
260 shift = 29, mask = 1,
261 [0] = {
262 shift = 31, mask = 1,
263 [0] = {
264 shift = 10, mask = 0x7ff,
265 [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg"
266 },
267 {
268 shift = 10, mask = 0x7ff,
269 [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg"
270 }
271 }
272}
273
274local map_data2s = { -- Data processing, 2 sources.
275 shift = 29, mask = 1,
276 [0] = {
277 shift = 10, mask = 63,
278 false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg",
279 "lsrDNMg", "asrDNMg", "rorDNMg"
280 }
281}
282
283local map_data3s = { -- Data processing, 3 sources.
284 shift = 29, mask = 7,
285 [0] = {
286 shift = 21, mask = 7,
287 [0] = {
288 shift = 15, mask = 1,
289 [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g"
290 }
291 }, false, false, false,
292 {
293 shift = 15, mask = 1,
294 [0] = {
295 shift = 21, mask = 7,
296 [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false,
297 false, "umaddl|umullDxNMwA0x", "umulhDNMx"
298 },
299 {
300 shift = 21, mask = 7,
301 [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false,
302 false, "umsubl|umneglDxNMwA0x"
303 }
304 }
305}
306
307local map_datar = { -- Data processing, register.
308 shift = 28, mask = 1,
309 [0] = {
310 shift = 24, mask = 1,
311 [0] = map_logsr,
312 {
313 shift = 21, mask = 1,
314 [0] = map_addsubsh, map_addsubex
315 }
316 },
317 {
318 shift = 21, mask = 15,
319 [0] = map_addsubc, false, map_ccomp, false, map_csel, false,
320 {
321 shift = 30, mask = 1,
322 [0] = map_data2s, map_data1s
323 },
324 false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s,
325 map_data3s, map_data3s, map_data3s
326 }
327}
328
329local map_lrl = { -- Load register, literal.
330 shift = 26, mask = 1,
331 [0] = {
332 shift = 30, mask = 3,
333 [0] = "ldrDwB", "ldrDxB", "ldrswDxB"
334 },
335 {
336 shift = 30, mask = 3,
337 [0] = "ldrDsB", "ldrDdB"
338 }
339}
340
341local map_lsriind = { -- Load/store register, immediate pre/post-indexed.
342 shift = 30, mask = 3,
343 [0] = {
344 shift = 26, mask = 1,
345 [0] = {
346 shift = 22, mask = 3,
347 [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL"
348 }
349 },
350 {
351 shift = 26, mask = 1,
352 [0] = {
353 shift = 22, mask = 3,
354 [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL"
355 }
356 },
357 {
358 shift = 26, mask = 1,
359 [0] = {
360 shift = 22, mask = 3,
361 [0] = "strDwzL", "ldrDwzL", "ldrswDxzL"
362 },
363 {
364 shift = 22, mask = 3,
365 [0] = "strDszL", "ldrDszL"
366 }
367 },
368 {
369 shift = 26, mask = 1,
370 [0] = {
371 shift = 22, mask = 3,
372 [0] = "strDxzL", "ldrDxzL"
373 },
374 {
375 shift = 22, mask = 3,
376 [0] = "strDdzL", "ldrDdzL"
377 }
378 }
379}
380
381local map_lsriro = {
382 shift = 21, mask = 1,
383 [0] = { -- Load/store register immediate.
384 shift = 10, mask = 3,
385 [0] = { -- Unscaled immediate.
386 shift = 26, mask = 1,
387 [0] = {
388 shift = 30, mask = 3,
389 [0] = {
390 shift = 22, mask = 3,
391 [0] = "sturbDwK", "ldurbDwK"
392 },
393 {
394 shift = 22, mask = 3,
395 [0] = "sturhDwK", "ldurhDwK"
396 },
397 {
398 shift = 22, mask = 3,
399 [0] = "sturDwK", "ldurDwK"
400 },
401 {
402 shift = 22, mask = 3,
403 [0] = "sturDxK", "ldurDxK"
404 }
405 }
406 }, map_lsriind, false, map_lsriind
407 },
408 { -- Load/store register, register offset.
409 shift = 10, mask = 3,
410 [2] = {
411 shift = 26, mask = 1,
412 [0] = {
413 shift = 30, mask = 3,
414 [1] = {
415 shift = 22, mask = 3,
416 [0] = "strhDwO", "ldrhDwO", "ldrshDwO", "ldrshDxO"
417 },
418 [2] = {
419 shift = 22, mask = 3,
420 [0] = "strDwO", "ldrDwO", "ldrswDxO"
421 },
422 [3] = {
423 shift = 22, mask = 3,
424 [0] = "strDxO", "ldrDxO"
425 }
426 },
427 {
428 shift = 30, mask = 3,
429 [2] = {
430 shift = 22, mask = 3,
431 [0] = "strDsO", "ldrDsO"
432 },
433 [3] = {
434 shift = 22, mask = 3,
435 [0] = "strDdO", "ldrDdO"
436 }
437 }
438 }
439 }
440}
441
442local map_lsp = { -- Load/store register pair, offset.
443 shift = 22, mask = 1,
444 [0] = {
445 shift = 30, mask = 3,
446 [0] = {
447 shift = 26, mask = 1,
448 [0] = "stpDzAzwP", "stpDzAzsP",
449 },
450 {
451 shift = 26, mask = 1,
452 "stpDzAzdP"
453 },
454 {
455 shift = 26, mask = 1,
456 [0] = "stpDzAzxP"
457 }
458 },
459 {
460 shift = 30, mask = 3,
461 [0] = {
462 shift = 26, mask = 1,
463 [0] = "ldpDzAzwP", "ldpDzAzsP",
464 },
465 {
466 shift = 26, mask = 1,
467 [0] = "ldpswDAxP", "ldpDzAzdP"
468 },
469 {
470 shift = 26, mask = 1,
471 [0] = "ldpDzAzxP"
472 }
473 }
474}
475
476local map_ls = { -- Loads and stores.
477 shift = 24, mask = 0x31,
478 [0x10] = map_lrl, [0x30] = map_lsriro,
479 [0x20] = {
480 shift = 23, mask = 3,
481 map_lsp, map_lsp, map_lsp
482 },
483 [0x21] = {
484 shift = 23, mask = 3,
485 map_lsp, map_lsp, map_lsp
486 },
487 [0x31] = {
488 shift = 26, mask = 1,
489 [0] = {
490 shift = 30, mask = 3,
491 [0] = {
492 shift = 22, mask = 3,
493 [0] = "strbDwzU", "ldrbDwzU"
494 },
495 {
496 shift = 22, mask = 3,
497 [0] = "strhDwzU", "ldrhDwzU"
498 },
499 {
500 shift = 22, mask = 3,
501 [0] = "strDwzU", "ldrDwzU"
502 },
503 {
504 shift = 22, mask = 3,
505 [0] = "strDxzU", "ldrDxzU"
506 }
507 },
508 {
509 shift = 30, mask = 3,
510 [2] = {
511 shift = 22, mask = 3,
512 [0] = "strDszU", "ldrDszU"
513 },
514 [3] = {
515 shift = 22, mask = 3,
516 [0] = "strDdzU", "ldrDdzU"
517 }
518 }
519 },
520}
521
522local map_datafp = { -- Data processing, SIMD and FP.
523 shift = 28, mask = 7,
524 { -- 001
525 shift = 24, mask = 1,
526 [0] = {
527 shift = 21, mask = 1,
528 {
529 shift = 10, mask = 3,
530 [0] = {
531 shift = 12, mask = 1,
532 [0] = {
533 shift = 13, mask = 1,
534 [0] = {
535 shift = 14, mask = 1,
536 [0] = {
537 shift = 15, mask = 1,
538 [0] = { -- FP/int conversion.
539 shift = 31, mask = 1,
540 [0] = {
541 shift = 16, mask = 0xff,
542 [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs",
543 [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw",
544 [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs",
545 [0x26] = "fmovDwNs", [0x27] = "fmovDsNw",
546 [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs",
547 [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs",
548 [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs",
549 [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd",
550 [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw",
551 [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd",
552 [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd",
553 [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd",
554 [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd"
555 },
556 {
557 shift = 16, mask = 0xff,
558 [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs",
559 [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx",
560 [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs",
561 [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs",
562 [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs",
563 [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs",
564 [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd",
565 [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx",
566 [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd",
567 [0x66] = "fmovDxNd", [0x67] = "fmovDdNx",
568 [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd",
569 [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd",
570 [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd"
571 }
572 }
573 },
574 { -- FP data-processing, 1 source.
575 shift = 31, mask = 1,
576 [0] = {
577 shift = 22, mask = 3,
578 [0] = {
579 shift = 15, mask = 63,
580 [0] = "fmovDNf", "fabsDNf", "fnegDNf",
581 "fsqrtDNf", false, "fcvtDdNs", false, false,
582 "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
583 "frintaDNf", false, "frintxDNf", "frintiDNf",
584 },
585 {
586 shift = 15, mask = 63,
587 [0] = "fmovDNf", "fabsDNf", "fnegDNf",
588 "fsqrtDNf", "fcvtDsNd", false, false, false,
589 "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
590 "frintaDNf", false, "frintxDNf", "frintiDNf",
591 }
592 }
593 }
594 },
595 { -- FP compare.
596 shift = 31, mask = 1,
597 [0] = {
598 shift = 14, mask = 3,
599 [0] = {
600 shift = 23, mask = 1,
601 [0] = {
602 shift = 0, mask = 31,
603 [0] = "fcmpNMf", [8] = "fcmpNZf",
604 [16] = "fcmpeNMf", [24] = "fcmpeNZf",
605 }
606 }
607 }
608 }
609 },
610 { -- FP immediate.
611 shift = 31, mask = 1,
612 [0] = {
613 shift = 5, mask = 31,
614 [0] = {
615 shift = 23, mask = 1,
616 [0] = "fmovDFf"
617 }
618 }
619 }
620 },
621 { -- FP conditional compare.
622 shift = 31, mask = 1,
623 [0] = {
624 shift = 23, mask = 1,
625 [0] = {
626 shift = 4, mask = 1,
627 [0] = "fccmpNMVCf", "fccmpeNMVCf"
628 }
629 }
630 },
631 { -- FP data-processing, 2 sources.
632 shift = 31, mask = 1,
633 [0] = {
634 shift = 23, mask = 1,
635 [0] = {
636 shift = 12, mask = 15,
637 [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf",
638 "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf",
639 "fnmulDNMf"
640 }
641 }
642 },
643 { -- FP conditional select.
644 shift = 31, mask = 1,
645 [0] = {
646 shift = 23, mask = 1,
647 [0] = "fcselDNMCf"
648 }
649 }
650 }
651 },
652 { -- FP data-processing, 3 sources.
653 shift = 31, mask = 1,
654 [0] = {
655 shift = 15, mask = 1,
656 [0] = {
657 shift = 21, mask = 5,
658 [0] = "fmaddDNMAf", "fnmaddDNMAf"
659 },
660 {
661 shift = 21, mask = 5,
662 [0] = "fmsubDNMAf", "fnmsubDNMAf"
663 }
664 }
665 }
666 }
667}
668
669local map_br = { -- Branches, exception generating and system instructions.
670 shift = 29, mask = 7,
671 [0] = "bB",
672 { -- Compare & branch, immediate.
673 shift = 24, mask = 3,
674 [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw"
675 },
676 { -- Conditional branch, immediate.
677 shift = 24, mask = 3,
678 [0] = {
679 shift = 4, mask = 1,
680 [0] = {
681 shift = 0, mask = 15,
682 [0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB",
683 "bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB"
684 }
685 }
686 }, false, "blB",
687 { -- Compare & branch, immediate.
688 shift = 24, mask = 3,
689 [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx"
690 },
691 {
692 shift = 24, mask = 3,
693 [0] = { -- Exception generation.
694 shift = 0, mask = 0xe0001f,
695 [0x200000] = "brkW"
696 },
697 { -- System instructions.
698 shift = 0, mask = 0x3fffff,
699 [0x03201f] = "nop"
700 },
701 { -- Unconditional branch, register.
702 shift = 0, mask = 0xfffc1f,
703 [0x1f0000] = "brNx", [0x3f0000] = "blrNx",
704 [0x5f0000] = "retNx"
705 },
706 }
707}
708
709local map_init = {
710 shift = 25, mask = 15,
711 [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp,
712 map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp
713}
714
715------------------------------------------------------------------------------
716
717local map_regs = { x = {}, w = {}, d = {}, s = {} }
718
719for i=0,30 do
720 map_regs.x[i] = "x"..i
721 map_regs.w[i] = "w"..i
722 map_regs.d[i] = "d"..i
723 map_regs.s[i] = "s"..i
724end
725map_regs.x[31] = "sp"
726map_regs.w[31] = "wsp"
727map_regs.d[31] = "d31"
728map_regs.s[31] = "s31"
729
730local map_cond = {
731 [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
732 "hi", "ls", "ge", "lt", "gt", "le", "al",
733}
734
735local map_shift = { [0] = "lsl", "lsr", "asr", }
736
737local map_extend = {
738 [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx",
739}
740
741------------------------------------------------------------------------------
742
743-- Output a nicely formatted line with an opcode and operands.
744local function putop(ctx, text, operands)
745 local pos = ctx.pos
746 local extra = ""
747 if ctx.rel then
748 local sym = ctx.symtab[ctx.rel]
749 if sym then
750 extra = "\t->"..sym
751 end
752 end
753 if ctx.hexdump > 0 then
754 ctx.out(format("%08x %s %-5s %s%s\n",
755 ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
756 else
757 ctx.out(format("%08x %-5s %s%s\n",
758 ctx.addr+pos, text, concat(operands, ", "), extra))
759 end
760 ctx.pos = pos + 4
761end
762
763-- Fallback for unknown opcodes.
764local function unknown(ctx)
765 return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
766end
767
768local function match_reg(p, pat, regnum)
769 return map_regs[match(pat, p.."%w-([xwds])")][regnum]
770end
771
772local function fmt_hex32(x)
773 if x < 0 then
774 return tohex(x)
775 else
776 return format("%x", x)
777 end
778end
779
780local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 }
781
782local function decode_imm13(op)
783 local imms = band(rshift(op, 10), 63)
784 local immr = band(rshift(op, 16), 63)
785 if band(op, 0x00400000) == 0 then
786 local len = 5
787 if imms >= 56 then
788 if imms >= 60 then len = 1 else len = 2 end
789 elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end
790 local l = lshift(1, len)-1
791 local s = band(imms, l)
792 local r = band(immr, l)
793 local imm = ror(rshift(-1, 31-s), r)
794 if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end
795 imm = imm * imm13_rep[len]
796 local ix = fmt_hex32(imm)
797 if rshift(op, 31) ~= 0 then
798 return ix..tohex(imm)
799 else
800 return ix
801 end
802 else
803 local lo, hi = -1, 0
804 if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end
805 if immr ~= 0 then
806 lo, hi = ror(lo, immr), ror(hi, immr)
807 local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr))
808 lo, hi = bxor(lo, x), bxor(hi, x)
809 if immr >= 32 then lo, hi = hi, lo end
810 end
811 if hi ~= 0 then
812 return fmt_hex32(hi)..tohex(lo)
813 else
814 return fmt_hex32(lo)
815 end
816 end
817end
818
819local function parse_immpc(op, name)
820 if name == "b" or name == "bl" then
821 return arshift(lshift(op, 6), 4)
822 elseif name == "adr" or name == "adrp" then
823 local immlo = band(rshift(op, 29), 3)
824 local immhi = lshift(arshift(lshift(op, 8), 13), 2)
825 return bor(immhi, immlo)
826 elseif name == "tbz" or name == "tbnz" then
827 return lshift(arshift(lshift(op, 13), 18), 2)
828 else
829 return lshift(arshift(lshift(op, 8), 13), 2)
830 end
831end
832
833local function parse_fpimm8(op)
834 local sign = band(op, 0x100000) == 0 and 1 or -1
835 local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131
836 local frac = 16+band(rshift(op, 13), 15)
837 return sign * frac * 2^exp
838end
839
840local function prefer_bfx(sf, uns, imms, immr)
841 if imms < immr or imms == 31 or imms == 63 then
842 return false
843 end
844 if immr == 0 then
845 if sf == 0 and (imms == 7 or imms == 15) then
846 return false
847 end
848 if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then
849 return false
850 end
851 end
852 return true
853end
854
855-- Disassemble a single instruction.
856local function disass_ins(ctx)
857 local pos = ctx.pos
858 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
859 local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
860 local operands = {}
861 local suffix = ""
862 local last, name, pat
863 local vr
864 local map_reg
865 ctx.op = op
866 ctx.rel = nil
867 last = nil
868 local opat
869 opat = map_init[band(rshift(op, 25), 15)]
870 while type(opat) ~= "string" do
871 if not opat then return unknown(ctx) end
872 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
873 end
874 name, pat = match(opat, "^([a-z0-9]*)(.*)")
875 local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
876 if altname then pat = pat2 end
877 if sub(pat, 1, 1) == "." then
878 local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
879 suffix = suffix..s2
880 pat = p2
881 end
882
883 local rt = match(pat, "[gf]")
884 if rt then
885 if rt == "g" then
886 map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w
887 else
888 map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s
889 end
890 end
891
892 local second0, immr
893
894 for p in gmatch(pat, ".") do
895 local x = nil
896 if p == "D" then
897 local regnum = band(op, 31)
898 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
899 elseif p == "N" then
900 local regnum = band(rshift(op, 5), 31)
901 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
902 elseif p == "M" then
903 local regnum = band(rshift(op, 16), 31)
904 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
905 elseif p == "A" then
906 local regnum = band(rshift(op, 10), 31)
907 x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
908 elseif p == "B" then
909 local addr = ctx.addr + pos + parse_immpc(op, name)
910 ctx.rel = addr
911 x = "0x"..tohex(addr)
912 elseif p == "T" then
913 x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31))
914 elseif p == "V" then
915 x = band(op, 15)
916 elseif p == "C" then
917 x = map_cond[band(rshift(op, 12), 15)]
918 elseif p == "c" then
919 local rn = band(rshift(op, 5), 31)
920 local rm = band(rshift(op, 16), 31)
921 local cond = band(rshift(op, 12), 15)
922 local invc = bxor(cond, 1)
923 x = map_cond[cond]
924 if altname and cond ~= 14 and cond ~= 15 then
925 local a1, a2 = match(altname, "([^|]*)|(.*)")
926 if rn == rm then
927 local n = #operands
928 operands[n] = nil
929 x = map_cond[invc]
930 if rn ~= 31 then
931 if a1 then name = a1 else name = altname end
932 else
933 operands[n-1] = nil
934 name = a2
935 end
936 end
937 end
938 elseif p == "W" then
939 x = band(rshift(op, 5), 0xffff)
940 elseif p == "Y" then
941 x = band(rshift(op, 5), 0xffff)
942 local hw = band(rshift(op, 21), 3)
943 if altname and (hw == 0 or x ~= 0) then
944 name = altname
945 end
946 elseif p == "L" then
947 local rn = map_regs.x[band(rshift(op, 5), 31)]
948 local imm9 = arshift(lshift(op, 11), 23)
949 if band(op, 0x800) ~= 0 then
950 x = "["..rn..", #"..imm9.."]!"
951 else
952 x = "["..rn.."], #"..imm9
953 end
954 elseif p == "U" then
955 local rn = map_regs.x[band(rshift(op, 5), 31)]
956 local sz = band(rshift(op, 30), 3)
957 local imm12 = lshift(arshift(lshift(op, 10), 20), sz)
958 if imm12 ~= 0 then
959 x = "["..rn..", #"..imm12.."]"
960 else
961 x = "["..rn.."]"
962 end
963 elseif p == "K" then
964 local rn = map_regs.x[band(rshift(op, 5), 31)]
965 local imm9 = arshift(lshift(op, 11), 23)
966 if imm9 ~= 0 then
967 x = "["..rn..", #"..imm9.."]"
968 else
969 x = "["..rn.."]"
970 end
971 elseif p == "O" then
972 local rn, rm = map_regs.x[band(rshift(op, 5), 31)]
973 local m = band(rshift(op, 13), 1)
974 if m == 0 then
975 rm = map_regs.w[band(rshift(op, 16), 31)]
976 else
977 rm = map_regs.x[band(rshift(op, 16), 31)]
978 end
979 x = "["..rn..", "..rm
980 local opt = band(rshift(op, 13), 7)
981 local s = band(rshift(op, 12), 1)
982 local sz = band(rshift(op, 30), 3)
983 -- extension to be applied
984 if opt == 3 then
985 if s == 0 then x = nil
986 else x = x..", lsl #"..sz.."]" end
987 elseif opt == 2 or opt == 6 or opt == 7 then
988 if s == 0 then x = x..", "..map_extend[opt].."]"
989 else x = x..", "..map_extend[opt].." #"..sz.."]" end
990 else
991 x = x.."]"
992 end
993 elseif p == "P" then
994 local opcv, sh = rshift(op, 26), 2
995 if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end
996 local imm7 = lshift(arshift(lshift(op, 10), 25), sh)
997 local rn = map_regs.x[band(rshift(op, 5), 31)]
998 local ind = band(rshift(op, 23), 3)
999 if ind == 1 then
1000 x = "["..rn.."], #"..imm7
1001 elseif ind == 2 then
1002 if imm7 == 0 then
1003 x = "["..rn.."]"
1004 else
1005 x = "["..rn..", #"..imm7.."]"
1006 end
1007 elseif ind == 3 then
1008 x = "["..rn..", #"..imm7.."]!"
1009 end
1010 elseif p == "I" then
1011 local shf = band(rshift(op, 22), 3)
1012 local imm12 = band(rshift(op, 10), 0x0fff)
1013 local n = #operands
1014 local rn, rd = band(rshift(op, 5), 31), band(op, 31)
1015 if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then
1016 name = altname
1017 x = nil
1018 elseif shf == 0 then
1019 x = imm12
1020 elseif shf == 1 then
1021 x = imm12..", lsl #12"
1022 end
1023 elseif p == "i" then
1024 x = "#0x"..decode_imm13(op)
1025 elseif p == "1" then
1026 immr = band(rshift(op, 16), 63)
1027 x = immr
1028 elseif p == "2" then
1029 x = band(rshift(op, 10), 63)
1030 if altname then
1031 local a1, a2, a3, a4, a5, a6 =
1032 match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)")
1033 local sf = band(rshift(op, 26), 32)
1034 local uns = band(rshift(op, 30), 1)
1035 if prefer_bfx(sf, uns, x, immr) then
1036 name = a2
1037 x = x - immr + 1
1038 elseif immr == 0 and x == 7 then
1039 local n = #operands
1040 operands[n] = nil
1041 if sf ~= 0 then
1042 operands[n-1] = gsub(operands[n-1], "x", "w")
1043 end
1044 last = operands[n-1]
1045 name = a6
1046 x = nil
1047 elseif immr == 0 and x == 15 then
1048 local n = #operands
1049 operands[n] = nil
1050 if sf ~= 0 then
1051 operands[n-1] = gsub(operands[n-1], "x", "w")
1052 end
1053 last = operands[n-1]
1054 name = a5
1055 x = nil
1056 elseif x == 31 or x == 63 then
1057 if x == 31 and immr == 0 and name == "sbfm" then
1058 name = a4
1059 local n = #operands
1060 operands[n] = nil
1061 if sf ~= 0 then
1062 operands[n-1] = gsub(operands[n-1], "x", "w")
1063 end
1064 last = operands[n-1]
1065 else
1066 name = a3
1067 end
1068 x = nil
1069 elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then
1070 name = a4
1071 last = "#"..(sf+32 - immr)
1072 operands[#operands] = last
1073 x = nil
1074 elseif x < immr then
1075 name = a1
1076 last = "#"..(sf+32 - immr)
1077 operands[#operands] = last
1078 x = x + 1
1079 end
1080 end
1081 elseif p == "3" then
1082 x = band(rshift(op, 10), 63)
1083 if altname then
1084 local a1, a2 = match(altname, "([^|]*)|(.*)")
1085 if x < immr then
1086 name = a1
1087 local sf = band(rshift(op, 26), 32)
1088 last = "#"..(sf+32 - immr)
1089 operands[#operands] = last
1090 x = x + 1
1091 elseif x >= immr then
1092 name = a2
1093 x = x - immr + 1
1094 end
1095 end
1096 elseif p == "4" then
1097 x = band(rshift(op, 10), 63)
1098 local rn = band(rshift(op, 5), 31)
1099 local rm = band(rshift(op, 16), 31)
1100 if altname and rn == rm then
1101 local n = #operands
1102 operands[n] = nil
1103 last = operands[n-1]
1104 name = altname
1105 end
1106 elseif p == "5" then
1107 x = band(rshift(op, 16), 31)
1108 elseif p == "S" then
1109 x = band(rshift(op, 10), 63)
1110 if x == 0 then x = nil
1111 else x = map_shift[band(rshift(op, 22), 3)].." #"..x end
1112 elseif p == "X" then
1113 local opt = band(rshift(op, 13), 7)
1114 -- Width specifier <R>.
1115 if opt ~= 3 and opt ~= 7 then
1116 last = map_regs.w[band(rshift(op, 16), 31)]
1117 operands[#operands] = last
1118 end
1119 x = band(rshift(op, 10), 7)
1120 -- Extension.
1121 if opt == 2 + band(rshift(op, 31), 1) and
1122 band(rshift(op, second0 and 5 or 0), 31) == 31 then
1123 if x == 0 then x = nil
1124 else x = "lsl #"..x end
1125 else
1126 if x == 0 then x = map_extend[band(rshift(op, 13), 7)]
1127 else x = map_extend[band(rshift(op, 13), 7)].." #"..x end
1128 end
1129 elseif p == "R" then
1130 x = band(rshift(op,21), 3)
1131 if x == 0 then x = nil
1132 else x = "lsl #"..x*16 end
1133 elseif p == "z" then
1134 local n = #operands
1135 if operands[n] == "sp" then operands[n] = "xzr"
1136 elseif operands[n] == "wsp" then operands[n] = "wzr"
1137 end
1138 elseif p == "Z" then
1139 x = 0
1140 elseif p == "F" then
1141 x = parse_fpimm8(op)
1142 elseif p == "g" or p == "f" or p == "x" or p == "w" or
1143 p == "d" or p == "s" then
1144 -- These are handled in D/N/M/A.
1145 elseif p == "0" then
1146 if last == "sp" or last == "wsp" then
1147 local n = #operands
1148 operands[n] = nil
1149 last = operands[n-1]
1150 if altname then
1151 local a1, a2 = match(altname, "([^|]*)|(.*)")
1152 if not a1 then
1153 name = altname
1154 elseif second0 then
1155 name, altname = a2, a1
1156 else
1157 name, altname = a1, a2
1158 end
1159 end
1160 end
1161 second0 = true
1162 else
1163 assert(false)
1164 end
1165 if x then
1166 last = x
1167 if type(x) == "number" then x = "#"..x end
1168 operands[#operands+1] = x
1169 end
1170 end
1171
1172 return putop(ctx, name..suffix, operands)
1173end
1174
1175------------------------------------------------------------------------------
1176
1177-- Disassemble a block of code.
1178local function disass_block(ctx, ofs, len)
1179 if not ofs then ofs = 0 end
1180 local stop = len and ofs+len or #ctx.code
1181 ctx.pos = ofs
1182 ctx.rel = nil
1183 while ctx.pos < stop do disass_ins(ctx) end
1184end
1185
1186-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
1187local function create(code, addr, out)
1188 local ctx = {}
1189 ctx.code = code
1190 ctx.addr = addr or 0
1191 ctx.out = out or io.write
1192 ctx.symtab = {}
1193 ctx.disass = disass_block
1194 ctx.hexdump = 8
1195 return ctx
1196end
1197
1198-- Simple API: disassemble code (a string) at address and output via out.
1199local function disass(code, addr, out)
1200 create(code, addr, out):disass()
1201end
1202
1203-- Return register name for RID.
1204local function regname(r)
1205 if r < 32 then return map_regs.x[r] end
1206 return map_regs.d[r-32]
1207end
1208
1209-- Public module functions.
1210return {
1211 create = create,
1212 disass = disass,
1213 regname = regname
1214}
1215