Mercurial
comparison third_party/luajit/src/jit/dis_arm.lua @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 ---------------------------------------------------------------------------- | |
| 2 -- LuaJIT ARM disassembler module. | |
| 3 -- | |
| 4 -- Copyright (C) 2005-2023 Mike Pall. All rights reserved. | |
| 5 -- Released under the MIT license. See Copyright Notice in luajit.h | |
| 6 ---------------------------------------------------------------------------- | |
| 7 -- This is a helper module used by the LuaJIT machine code dumper module. | |
| 8 -- | |
| 9 -- It disassembles most user-mode ARMv7 instructions | |
| 10 -- NYI: Advanced SIMD and VFP instructions. | |
| 11 ------------------------------------------------------------------------------ | |
| 12 | |
| 13 local type = type | |
| 14 local sub, byte, format = string.sub, string.byte, string.format | |
| 15 local match, gmatch = string.match, string.gmatch | |
| 16 local concat = table.concat | |
| 17 local bit = require("bit") | |
| 18 local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex | |
| 19 local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift | |
| 20 | |
| 21 ------------------------------------------------------------------------------ | |
| 22 -- Opcode maps | |
| 23 ------------------------------------------------------------------------------ | |
| 24 | |
| 25 local map_loadc = { | |
| 26 shift = 8, mask = 15, | |
| 27 [10] = { | |
| 28 shift = 20, mask = 1, | |
| 29 [0] = { | |
| 30 shift = 23, mask = 3, | |
| 31 [0] = "vmovFmDN", "vstmFNdr", | |
| 32 _ = { | |
| 33 shift = 21, mask = 1, | |
| 34 [0] = "vstrFdl", | |
| 35 { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", } | |
| 36 }, | |
| 37 }, | |
| 38 { | |
| 39 shift = 23, mask = 3, | |
| 40 [0] = "vmovFDNm", | |
| 41 { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", }, | |
| 42 _ = { | |
| 43 shift = 21, mask = 1, | |
| 44 [0] = "vldrFdl", "vldmdbFNdr", | |
| 45 }, | |
| 46 }, | |
| 47 }, | |
| 48 [11] = { | |
| 49 shift = 20, mask = 1, | |
| 50 [0] = { | |
| 51 shift = 23, mask = 3, | |
| 52 [0] = "vmovGmDN", "vstmGNdr", | |
| 53 _ = { | |
| 54 shift = 21, mask = 1, | |
| 55 [0] = "vstrGdl", | |
| 56 { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", } | |
| 57 }, | |
| 58 }, | |
| 59 { | |
| 60 shift = 23, mask = 3, | |
| 61 [0] = "vmovGDNm", | |
| 62 { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", }, | |
| 63 _ = { | |
| 64 shift = 21, mask = 1, | |
| 65 [0] = "vldrGdl", "vldmdbGNdr", | |
| 66 }, | |
| 67 }, | |
| 68 }, | |
| 69 _ = { | |
| 70 shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc. | |
| 71 }, | |
| 72 } | |
| 73 | |
| 74 local map_vfps = { | |
| 75 shift = 6, mask = 0x2c001, | |
| 76 [0] = "vmlaF.dnm", "vmlsF.dnm", | |
| 77 [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm", | |
| 78 [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm", | |
| 79 [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm", | |
| 80 [0x20000] = "vdivF.dnm", | |
| 81 [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm", | |
| 82 [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm", | |
| 83 [0x2c000] = "vmovF.dY", | |
| 84 [0x2c001] = { | |
| 85 shift = 7, mask = 0x1e01, | |
| 86 [0] = "vmovF.dm", "vabsF.dm", | |
| 87 [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm", | |
| 88 [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm", | |
| 89 [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d", | |
| 90 [0x0e01] = "vcvtG.dF.m", | |
| 91 [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm", | |
| 92 [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm", | |
| 93 [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm", | |
| 94 }, | |
| 95 } | |
| 96 | |
| 97 local map_vfpd = { | |
| 98 shift = 6, mask = 0x2c001, | |
| 99 [0] = "vmlaG.dnm", "vmlsG.dnm", | |
| 100 [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm", | |
| 101 [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm", | |
| 102 [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm", | |
| 103 [0x20000] = "vdivG.dnm", | |
| 104 [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm", | |
| 105 [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm", | |
| 106 [0x2c000] = "vmovG.dY", | |
| 107 [0x2c001] = { | |
| 108 shift = 7, mask = 0x1e01, | |
| 109 [0] = "vmovG.dm", "vabsG.dm", | |
| 110 [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm", | |
| 111 [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm", | |
| 112 [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d", | |
| 113 [0x0e01] = "vcvtF.dG.m", | |
| 114 [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm", | |
| 115 [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m", | |
| 116 [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m", | |
| 117 }, | |
| 118 } | |
| 119 | |
| 120 local map_datac = { | |
| 121 shift = 24, mask = 1, | |
| 122 [0] = { | |
| 123 shift = 4, mask = 1, | |
| 124 [0] = { | |
| 125 shift = 8, mask = 15, | |
| 126 [10] = map_vfps, | |
| 127 [11] = map_vfpd, | |
| 128 -- NYI cdp, mcr, mrc. | |
| 129 }, | |
| 130 { | |
| 131 shift = 8, mask = 15, | |
| 132 [10] = { | |
| 133 shift = 20, mask = 15, | |
| 134 [0] = "vmovFnD", "vmovFDn", | |
| 135 [14] = "vmsrD", | |
| 136 [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", }, | |
| 137 }, | |
| 138 }, | |
| 139 }, | |
| 140 "svcT", | |
| 141 } | |
| 142 | |
| 143 local map_loadcu = { | |
| 144 shift = 0, mask = 0, -- NYI unconditional CP load/store. | |
| 145 } | |
| 146 | |
| 147 local map_datacu = { | |
| 148 shift = 0, mask = 0, -- NYI unconditional CP data. | |
| 149 } | |
| 150 | |
| 151 local map_simddata = { | |
| 152 shift = 0, mask = 0, -- NYI SIMD data. | |
| 153 } | |
| 154 | |
| 155 local map_simdload = { | |
| 156 shift = 0, mask = 0, -- NYI SIMD load/store, preload. | |
| 157 } | |
| 158 | |
| 159 local map_preload = { | |
| 160 shift = 0, mask = 0, -- NYI preload. | |
| 161 } | |
| 162 | |
| 163 local map_media = { | |
| 164 shift = 20, mask = 31, | |
| 165 [0] = false, | |
| 166 { --01 | |
| 167 shift = 5, mask = 7, | |
| 168 [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM", | |
| 169 "sadd8DNM", false, false, "ssub8DNM", | |
| 170 }, | |
| 171 { --02 | |
| 172 shift = 5, mask = 7, | |
| 173 [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM", | |
| 174 "qadd8DNM", false, false, "qsub8DNM", | |
| 175 }, | |
| 176 { --03 | |
| 177 shift = 5, mask = 7, | |
| 178 [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM", | |
| 179 "shadd8DNM", false, false, "shsub8DNM", | |
| 180 }, | |
| 181 false, | |
| 182 { --05 | |
| 183 shift = 5, mask = 7, | |
| 184 [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM", | |
| 185 "uadd8DNM", false, false, "usub8DNM", | |
| 186 }, | |
| 187 { --06 | |
| 188 shift = 5, mask = 7, | |
| 189 [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM", | |
| 190 "uqadd8DNM", false, false, "uqsub8DNM", | |
| 191 }, | |
| 192 { --07 | |
| 193 shift = 5, mask = 7, | |
| 194 [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM", | |
| 195 "uhadd8DNM", false, false, "uhsub8DNM", | |
| 196 }, | |
| 197 { --08 | |
| 198 shift = 5, mask = 7, | |
| 199 [0] = "pkhbtDNMU", false, "pkhtbDNMU", | |
| 200 { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", }, | |
| 201 "pkhbtDNMU", "selDNM", "pkhtbDNMU", | |
| 202 }, | |
| 203 false, | |
| 204 { --0a | |
| 205 shift = 5, mask = 7, | |
| 206 [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu", | |
| 207 { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", }, | |
| 208 "ssatDxMu", false, "ssatDxMu", | |
| 209 }, | |
| 210 { --0b | |
| 211 shift = 5, mask = 7, | |
| 212 [0] = "ssatDxMu", "revDM", "ssatDxMu", | |
| 213 { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", }, | |
| 214 "ssatDxMu", "rev16DM", "ssatDxMu", | |
| 215 }, | |
| 216 { --0c | |
| 217 shift = 5, mask = 7, | |
| 218 [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", }, | |
| 219 }, | |
| 220 false, | |
| 221 { --0e | |
| 222 shift = 5, mask = 7, | |
| 223 [0] = "usatDwMu", "usat16DwM", "usatDwMu", | |
| 224 { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", }, | |
| 225 "usatDwMu", false, "usatDwMu", | |
| 226 }, | |
| 227 { --0f | |
| 228 shift = 5, mask = 7, | |
| 229 [0] = "usatDwMu", "rbitDM", "usatDwMu", | |
| 230 { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", }, | |
| 231 "usatDwMu", "revshDM", "usatDwMu", | |
| 232 }, | |
| 233 { --10 | |
| 234 shift = 12, mask = 15, | |
| 235 [15] = { | |
| 236 shift = 5, mask = 7, | |
| 237 "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS", | |
| 238 }, | |
| 239 _ = { | |
| 240 shift = 5, mask = 7, | |
| 241 [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD", | |
| 242 }, | |
| 243 }, | |
| 244 false, false, false, | |
| 245 { --14 | |
| 246 shift = 5, mask = 7, | |
| 247 [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS", | |
| 248 }, | |
| 249 { --15 | |
| 250 shift = 5, mask = 7, | |
| 251 [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", }, | |
| 252 { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", }, | |
| 253 false, false, false, false, | |
| 254 "smmlsNMSD", "smmlsrNMSD", | |
| 255 }, | |
| 256 false, false, | |
| 257 { --18 | |
| 258 shift = 5, mask = 7, | |
| 259 [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", }, | |
| 260 }, | |
| 261 false, | |
| 262 { --1a | |
| 263 shift = 5, mask = 3, [2] = "sbfxDMvw", | |
| 264 }, | |
| 265 { --1b | |
| 266 shift = 5, mask = 3, [2] = "sbfxDMvw", | |
| 267 }, | |
| 268 { --1c | |
| 269 shift = 5, mask = 3, | |
| 270 [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, | |
| 271 }, | |
| 272 { --1d | |
| 273 shift = 5, mask = 3, | |
| 274 [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, | |
| 275 }, | |
| 276 { --1e | |
| 277 shift = 5, mask = 3, [2] = "ubfxDMvw", | |
| 278 }, | |
| 279 { --1f | |
| 280 shift = 5, mask = 3, [2] = "ubfxDMvw", | |
| 281 }, | |
| 282 } | |
| 283 | |
| 284 local map_load = { | |
| 285 shift = 21, mask = 9, | |
| 286 { | |
| 287 shift = 20, mask = 5, | |
| 288 [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL", | |
| 289 }, | |
| 290 _ = { | |
| 291 shift = 20, mask = 5, | |
| 292 [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL", | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 local map_load1 = { | |
| 297 shift = 4, mask = 1, | |
| 298 [0] = map_load, map_media, | |
| 299 } | |
| 300 | |
| 301 local map_loadm = { | |
| 302 shift = 20, mask = 1, | |
| 303 [0] = { | |
| 304 shift = 23, mask = 3, | |
| 305 [0] = "stmdaNR", "stmNR", | |
| 306 { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR", | |
| 307 }, | |
| 308 { | |
| 309 shift = 23, mask = 3, | |
| 310 [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", }, | |
| 311 "ldmdbNR", "ldmibNR", | |
| 312 }, | |
| 313 } | |
| 314 | |
| 315 local map_data = { | |
| 316 shift = 21, mask = 15, | |
| 317 [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs", | |
| 318 "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs", | |
| 319 "tstNP", "teqNP", "cmpNP", "cmnNP", | |
| 320 "orrDNPs", "movDPs", "bicDNPs", "mvnDPs", | |
| 321 } | |
| 322 | |
| 323 local map_mul = { | |
| 324 shift = 21, mask = 7, | |
| 325 [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS", | |
| 326 "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs", | |
| 327 } | |
| 328 | |
| 329 local map_sync = { | |
| 330 shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd. | |
| 331 [0] = "swpDMN", false, false, false, | |
| 332 "swpbDMN", false, false, false, | |
| 333 "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN", | |
| 334 "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN", | |
| 335 } | |
| 336 | |
| 337 local map_mulh = { | |
| 338 shift = 21, mask = 3, | |
| 339 [0] = { shift = 5, mask = 3, | |
| 340 [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", }, | |
| 341 { shift = 5, mask = 3, | |
| 342 [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", }, | |
| 343 { shift = 5, mask = 3, | |
| 344 [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", }, | |
| 345 { shift = 5, mask = 3, | |
| 346 [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", }, | |
| 347 } | |
| 348 | |
| 349 local map_misc = { | |
| 350 shift = 4, mask = 7, | |
| 351 -- NYI: decode PSR bits of msr. | |
| 352 [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", }, | |
| 353 { shift = 21, mask = 3, "bxM", false, "clzDM", }, | |
| 354 { shift = 21, mask = 3, "bxjM", }, | |
| 355 { shift = 21, mask = 3, "blxM", }, | |
| 356 false, | |
| 357 { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", }, | |
| 358 false, | |
| 359 { shift = 21, mask = 3, "bkptK", }, | |
| 360 } | |
| 361 | |
| 362 local map_datar = { | |
| 363 shift = 4, mask = 9, | |
| 364 [9] = { | |
| 365 shift = 5, mask = 3, | |
| 366 [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, }, | |
| 367 { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", }, | |
| 368 { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", }, | |
| 369 { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", }, | |
| 370 }, | |
| 371 _ = { | |
| 372 shift = 20, mask = 25, | |
| 373 [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, }, | |
| 374 _ = { | |
| 375 shift = 0, mask = 0xffffffff, | |
| 376 [bor(0xe1a00000)] = "nop", | |
| 377 _ = map_data, | |
| 378 } | |
| 379 }, | |
| 380 } | |
| 381 | |
| 382 local map_datai = { | |
| 383 shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12. | |
| 384 [16] = "movwDW", [20] = "movtDW", | |
| 385 [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", }, | |
| 386 [22] = "msrNW", | |
| 387 _ = map_data, | |
| 388 } | |
| 389 | |
| 390 local map_branch = { | |
| 391 shift = 24, mask = 1, | |
| 392 [0] = "bB", "blB" | |
| 393 } | |
| 394 | |
| 395 local map_condins = { | |
| 396 [0] = map_datar, map_datai, map_load, map_load1, | |
| 397 map_loadm, map_branch, map_loadc, map_datac | |
| 398 } | |
| 399 | |
| 400 -- NYI: setend. | |
| 401 local map_uncondins = { | |
| 402 [0] = false, map_simddata, map_simdload, map_preload, | |
| 403 false, "blxB", map_loadcu, map_datacu, | |
| 404 } | |
| 405 | |
| 406 ------------------------------------------------------------------------------ | |
| 407 | |
| 408 local map_gpr = { | |
| 409 [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
| 410 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", | |
| 411 } | |
| 412 | |
| 413 local map_cond = { | |
| 414 [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", | |
| 415 "hi", "ls", "ge", "lt", "gt", "le", "al", | |
| 416 } | |
| 417 | |
| 418 local map_shift = { [0] = "lsl", "lsr", "asr", "ror", } | |
| 419 | |
| 420 ------------------------------------------------------------------------------ | |
| 421 | |
| 422 -- Output a nicely formatted line with an opcode and operands. | |
| 423 local function putop(ctx, text, operands) | |
| 424 local pos = ctx.pos | |
| 425 local extra = "" | |
| 426 if ctx.rel then | |
| 427 local sym = ctx.symtab[ctx.rel] | |
| 428 if sym then | |
| 429 extra = "\t->"..sym | |
| 430 elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then | |
| 431 extra = "\t; 0x"..tohex(ctx.rel) | |
| 432 end | |
| 433 end | |
| 434 if ctx.hexdump > 0 then | |
| 435 ctx.out(format("%08x %s %-5s %s%s\n", | |
| 436 ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) | |
| 437 else | |
| 438 ctx.out(format("%08x %-5s %s%s\n", | |
| 439 ctx.addr+pos, text, concat(operands, ", "), extra)) | |
| 440 end | |
| 441 ctx.pos = pos + 4 | |
| 442 end | |
| 443 | |
| 444 -- Fallback for unknown opcodes. | |
| 445 local function unknown(ctx) | |
| 446 return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) | |
| 447 end | |
| 448 | |
| 449 -- Format operand 2 of load/store opcodes. | |
| 450 local function fmtload(ctx, op, pos) | |
| 451 local base = map_gpr[band(rshift(op, 16), 15)] | |
| 452 local x, ofs | |
| 453 local ext = (band(op, 0x04000000) == 0) | |
| 454 if not ext and band(op, 0x02000000) == 0 then | |
| 455 ofs = band(op, 4095) | |
| 456 if band(op, 0x00800000) == 0 then ofs = -ofs end | |
| 457 if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end | |
| 458 ofs = "#"..ofs | |
| 459 elseif ext and band(op, 0x00400000) ~= 0 then | |
| 460 ofs = band(op, 15) + band(rshift(op, 4), 0xf0) | |
| 461 if band(op, 0x00800000) == 0 then ofs = -ofs end | |
| 462 if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end | |
| 463 ofs = "#"..ofs | |
| 464 else | |
| 465 ofs = map_gpr[band(op, 15)] | |
| 466 if ext or band(op, 0xfe0) == 0 then | |
| 467 elseif band(op, 0xfe0) == 0x60 then | |
| 468 ofs = format("%s, rrx", ofs) | |
| 469 else | |
| 470 local sh = band(rshift(op, 7), 31) | |
| 471 if sh == 0 then sh = 32 end | |
| 472 ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh) | |
| 473 end | |
| 474 if band(op, 0x00800000) == 0 then ofs = "-"..ofs end | |
| 475 end | |
| 476 if ofs == "#0" then | |
| 477 x = format("[%s]", base) | |
| 478 elseif band(op, 0x01000000) == 0 then | |
| 479 x = format("[%s], %s", base, ofs) | |
| 480 else | |
| 481 x = format("[%s, %s]", base, ofs) | |
| 482 end | |
| 483 if band(op, 0x01200000) == 0x01200000 then x = x.."!" end | |
| 484 return x | |
| 485 end | |
| 486 | |
| 487 -- Format operand 2 of vector load/store opcodes. | |
| 488 local function fmtvload(ctx, op, pos) | |
| 489 local base = map_gpr[band(rshift(op, 16), 15)] | |
| 490 local ofs = band(op, 255)*4 | |
| 491 if band(op, 0x00800000) == 0 then ofs = -ofs end | |
| 492 if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end | |
| 493 if ofs == 0 then | |
| 494 return format("[%s]", base) | |
| 495 else | |
| 496 return format("[%s, #%d]", base, ofs) | |
| 497 end | |
| 498 end | |
| 499 | |
| 500 local function fmtvr(op, vr, sh0, sh1) | |
| 501 if vr == "s" then | |
| 502 return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1)) | |
| 503 else | |
| 504 return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16)) | |
| 505 end | |
| 506 end | |
| 507 | |
| 508 -- Disassemble a single instruction. | |
| 509 local function disass_ins(ctx) | |
| 510 local pos = ctx.pos | |
| 511 local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) | |
| 512 local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) | |
| 513 local operands = {} | |
| 514 local suffix = "" | |
| 515 local last, name, pat | |
| 516 local vr | |
| 517 ctx.op = op | |
| 518 ctx.rel = nil | |
| 519 | |
| 520 local cond = rshift(op, 28) | |
| 521 local opat | |
| 522 if cond == 15 then | |
| 523 opat = map_uncondins[band(rshift(op, 25), 7)] | |
| 524 else | |
| 525 if cond ~= 14 then suffix = map_cond[cond] end | |
| 526 opat = map_condins[band(rshift(op, 25), 7)] | |
| 527 end | |
| 528 while type(opat) ~= "string" do | |
| 529 if not opat then return unknown(ctx) end | |
| 530 opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ | |
| 531 end | |
| 532 name, pat = match(opat, "^([a-z0-9]*)(.*)") | |
| 533 if sub(pat, 1, 1) == "." then | |
| 534 local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") | |
| 535 suffix = suffix..s2 | |
| 536 pat = p2 | |
| 537 end | |
| 538 | |
| 539 for p in gmatch(pat, ".") do | |
| 540 local x = nil | |
| 541 if p == "D" then | |
| 542 x = map_gpr[band(rshift(op, 12), 15)] | |
| 543 elseif p == "N" then | |
| 544 x = map_gpr[band(rshift(op, 16), 15)] | |
| 545 elseif p == "S" then | |
| 546 x = map_gpr[band(rshift(op, 8), 15)] | |
| 547 elseif p == "M" then | |
| 548 x = map_gpr[band(op, 15)] | |
| 549 elseif p == "d" then | |
| 550 x = fmtvr(op, vr, 12, 22) | |
| 551 elseif p == "n" then | |
| 552 x = fmtvr(op, vr, 16, 7) | |
| 553 elseif p == "m" then | |
| 554 x = fmtvr(op, vr, 0, 5) | |
| 555 elseif p == "P" then | |
| 556 if band(op, 0x02000000) ~= 0 then | |
| 557 x = ror(band(op, 255), 2*band(rshift(op, 8), 15)) | |
| 558 else | |
| 559 x = map_gpr[band(op, 15)] | |
| 560 if band(op, 0xff0) ~= 0 then | |
| 561 operands[#operands+1] = x | |
| 562 local s = map_shift[band(rshift(op, 5), 3)] | |
| 563 local r = nil | |
| 564 if band(op, 0xf90) == 0 then | |
| 565 if s == "ror" then s = "rrx" else r = "#32" end | |
| 566 elseif band(op, 0x10) == 0 then | |
| 567 r = "#"..band(rshift(op, 7), 31) | |
| 568 else | |
| 569 r = map_gpr[band(rshift(op, 8), 15)] | |
| 570 end | |
| 571 if name == "mov" then name = s; x = r | |
| 572 elseif r then x = format("%s %s", s, r) | |
| 573 else x = s end | |
| 574 end | |
| 575 end | |
| 576 elseif p == "L" then | |
| 577 x = fmtload(ctx, op, pos) | |
| 578 elseif p == "l" then | |
| 579 x = fmtvload(ctx, op, pos) | |
| 580 elseif p == "B" then | |
| 581 local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6) | |
| 582 if cond == 15 then addr = addr + band(rshift(op, 23), 2) end | |
| 583 ctx.rel = addr | |
| 584 x = "0x"..tohex(addr) | |
| 585 elseif p == "F" then | |
| 586 vr = "s" | |
| 587 elseif p == "G" then | |
| 588 vr = "d" | |
| 589 elseif p == "." then | |
| 590 suffix = suffix..(vr == "s" and ".f32" or ".f64") | |
| 591 elseif p == "R" then | |
| 592 if band(op, 0x00200000) ~= 0 and #operands == 1 then | |
| 593 operands[1] = operands[1].."!" | |
| 594 end | |
| 595 local t = {} | |
| 596 for i=0,15 do | |
| 597 if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end | |
| 598 end | |
| 599 x = "{"..concat(t, ", ").."}" | |
| 600 elseif p == "r" then | |
| 601 if band(op, 0x00200000) ~= 0 and #operands == 2 then | |
| 602 operands[1] = operands[1].."!" | |
| 603 end | |
| 604 local s = tonumber(sub(last, 2)) | |
| 605 local n = band(op, 255) | |
| 606 if vr == "d" then n = rshift(n, 1) end | |
| 607 operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1) | |
| 608 elseif p == "W" then | |
| 609 x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000) | |
| 610 elseif p == "T" then | |
| 611 x = "#0x"..tohex(band(op, 0x00ffffff), 6) | |
| 612 elseif p == "U" then | |
| 613 x = band(rshift(op, 7), 31) | |
| 614 if x == 0 then x = nil end | |
| 615 elseif p == "u" then | |
| 616 x = band(rshift(op, 7), 31) | |
| 617 if band(op, 0x40) == 0 then | |
| 618 if x == 0 then x = nil else x = "lsl #"..x end | |
| 619 else | |
| 620 if x == 0 then x = "asr #32" else x = "asr #"..x end | |
| 621 end | |
| 622 elseif p == "v" then | |
| 623 x = band(rshift(op, 7), 31) | |
| 624 elseif p == "w" then | |
| 625 x = band(rshift(op, 16), 31) | |
| 626 elseif p == "x" then | |
| 627 x = band(rshift(op, 16), 31) + 1 | |
| 628 elseif p == "X" then | |
| 629 x = band(rshift(op, 16), 31) - last + 1 | |
| 630 elseif p == "Y" then | |
| 631 x = band(rshift(op, 12), 0xf0) + band(op, 0x0f) | |
| 632 elseif p == "K" then | |
| 633 x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4) | |
| 634 elseif p == "s" then | |
| 635 if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end | |
| 636 else | |
| 637 assert(false) | |
| 638 end | |
| 639 if x then | |
| 640 last = x | |
| 641 if type(x) == "number" then x = "#"..x end | |
| 642 operands[#operands+1] = x | |
| 643 end | |
| 644 end | |
| 645 | |
| 646 return putop(ctx, name..suffix, operands) | |
| 647 end | |
| 648 | |
| 649 ------------------------------------------------------------------------------ | |
| 650 | |
| 651 -- Disassemble a block of code. | |
| 652 local function disass_block(ctx, ofs, len) | |
| 653 if not ofs then ofs = 0 end | |
| 654 local stop = len and ofs+len or #ctx.code | |
| 655 ctx.pos = ofs | |
| 656 ctx.rel = nil | |
| 657 while ctx.pos < stop do disass_ins(ctx) end | |
| 658 end | |
| 659 | |
| 660 -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). | |
| 661 local function create(code, addr, out) | |
| 662 local ctx = {} | |
| 663 ctx.code = code | |
| 664 ctx.addr = addr or 0 | |
| 665 ctx.out = out or io.write | |
| 666 ctx.symtab = {} | |
| 667 ctx.disass = disass_block | |
| 668 ctx.hexdump = 8 | |
| 669 return ctx | |
| 670 end | |
| 671 | |
| 672 -- Simple API: disassemble code (a string) at address and output via out. | |
| 673 local function disass(code, addr, out) | |
| 674 create(code, addr, out):disass() | |
| 675 end | |
| 676 | |
| 677 -- Return register name for RID. | |
| 678 local function regname(r) | |
| 679 if r < 16 then return map_gpr[r] end | |
| 680 return "d"..(r-16) | |
| 681 end | |
| 682 | |
| 683 -- Public module functions. | |
| 684 return { | |
| 685 create = create, | |
| 686 disass = disass, | |
| 687 regname = regname | |
| 688 } | |
| 689 |