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