---------------------------------------------------------------------------- -- LuaJIT PPC disassembler module. -- -- Copyright (C) 2005-2015 Mike Pall. All rights reserved. -- Released under the MIT/X license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -- This is a helper module used by the LuaJIT machine code dumper module. -- -- It disassembles all common, non-privileged 32/64 bit PowerPC instructions -- plus the e500 SPE instructions and some Cell/Xenon extensions. -- -- NYI: VMX, VMX128 ------------------------------------------------------------------------------ local type = type local sub, byte, format = string.sub, string.byte, string.format local match, gmatch, gsub = string.match, string.gmatch, string.gsub local concat = table.concat local bit = require("bit") local band, bor, tohex = bit.band, bit.bor, bit.tohex local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift ------------------------------------------------------------------------------ -- Primary and extended opcode maps ------------------------------------------------------------------------------ local map_crops = { shift = 1, mask = 1023, [0] = "mcrfXX", [33] = "crnor|crnotCCC=", [129] = "crandcCCC", [193] = "crxor|crclrCCC%", [225] = "crnandCCC", [257] = "crandCCC", [289] = "creqv|crsetCCC%", [417] = "crorcCCC", [449] = "cror|crmoveCCC=", [16] = "b_lrKB", [528] = "b_ctrKB", [150] = "isync", } local map_rlwinm = setmetatable({ shift = 0, mask = -1, }, { __index = function(t, x) local rot = band(rshift(x, 11), 31) local mb = band(rshift(x, 6), 31) local me = band(rshift(x, 1), 31) if mb == 0 and me == 31-rot then return "slwiRR~A." elseif me == 31 and mb == 32-rot then return "srwiRR~-A." else return "rlwinmRR~AAA." end end }) local map_rld = { shift = 2, mask = 7, [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", { shift = 1, mask = 1, [0] = "rldclRR~RM.", "rldcrRR~RM.", }, } local map_ext = setmetatable({ shift = 1, mask = 1023, [0] = "cmp_YLRR", [32] = "cmpl_YLRR", [4] = "twARR", [68] = "tdARR", [8] = "subfcRRR.", [40] = "subfRRR.", [104] = "negRR.", [136] = "subfeRRR.", [200] = "subfzeRR.", [232] = "subfmeRR.", [520] = "subfcoRRR.", [552] = "subfoRRR.", [616] = "negoRR.", [648] = "subfeoRRR.", [712] = "subfzeoRR.", [744] = "subfmeoRR.", [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", [457] = "divduRRR.", [489] = "divdRRR.", [745] = "mulldoRRR.", [969] = "divduoRRR.", [1001] = "divdoRRR.", [10] = "addcRRR.", [138] = "addeRRR.", [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", [522] = "addcoRRR.", [650] = "addeoRRR.", [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", [459] = "divwuRRR.", [491] = "divwRRR.", [747] = "mullwoRRR.", [971] = "divwouRRR.", [1003] = "divwoRRR.", [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", }, [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", }, [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", }, [339] = { shift = 11, mask = 1023, [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR", }, [467] = { shift = 11, mask = 1023, [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", }, [20] = "lwarxRR0R", [84] = "ldarxRR0R", [21] = "ldxRR0R", [53] = "lduxRRR", [149] = "stdxRR0R", [181] = "stduxRRR", [341] = "lwaxRR0R", [373] = "lwauxRRR", [23] = "lwzxRR0R", [55] = "lwzuxRRR", [87] = "lbzxRR0R", [119] = "lbzuxRRR", [151] = "stwxRR0R", [183] = "stwuxRRR", [215] = "stbxRR0R", [247] = "stbuxRRR", [279] = "lhzxRR0R", [311] = "lhzuxRRR", [343] = "lhaxRR0R", [375] = "lhauxRRR", [407] = "sthxRR0R", [439] = "sthuxRRR", [54] = "dcbst-R0R", [86] = "dcbf-R0R", [150] = "stwcxRR0R.", [214] = "stdcxRR0R.", [246] = "dcbtst-R0R", [278] = "dcbt-R0R", [310] = "eciwxRR0R", [438] = "ecowxRR0R", [470] = "dcbi-RR", [598] = { shift = 21, mask = 3, [0] = "sync", "lwsync", "ptesync", }, [758] = "dcba-RR", [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", [26] = "cntlzwRR~", [58] = "cntlzdRR~", [122] = "popcntbRR~", [154] = "prtywRR~", [186] = "prtydRR~", [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.", [284] = "eqvRR~R.", [316] = "xorRR~R.", [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.", [508] = "cmpbRR~R", [512] = "mcrxrX", [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", [533] = "lswxRR0R", [597] = "lswiRR0A", [661] = "stswxRR0R", [725] = "stswiRR0A", [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", [535] = "lfsxFR0R", [567] = "lfsuxFRR", [599] = "lfdxFR0R", [631] = "lfduxFRR", [663] = "stfsxFR0R", [695] = "stfsuxFRR", [727] = "stfdxFR0R", [759] = "stfduxFR0R", [855] = "lfiwaxFR0R", [983] = "stfiwxFR0R", [24] = "slwRR~R.", [27] = "sldRR~R.", [536] = "srwRR~R.", [792] = "srawRR~R.", [824] = "srawiRR~A.", [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", [539] = "srdRR~R.", }, { __index = function(t, x) if band(x, 31) == 15 then return "iselRRRC" end end }) local map_ld = { shift = 0, mask = 3, [0] = "ldRRE", "lduRRE", "lwaRRE", } local map_std = { shift = 0, mask = 3, [0] = "stdRRE", "stduRRE", } local map_fps = { shift = 5, mask = 1, { shift = 1, mask = 15, [0] = false, false, "fdivsFFF.", false, "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false, "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false, "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.", } } local map_fpd = { shift = 5, mask = 1, [0] = { shift = 1, mask = 1023, [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX", [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>", [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.", [136] = "fnabsF-F.", [264] = "fabsF-F.", [12] = "frspF-F.", [14] = "fctiwF-F.", [15] = "fctiwzF-F.", [583] = "mffsF.", [711] = "mtfsfZF.", [392] = "frinF-F.", [424] = "frizF-F.", [456] = "fripF-F.", [488] = "frimF-F.", [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.", }, { shift = 1, mask = 15, [0] = false, false, "fdivFFF.", false, "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.", "freF-F.", "fmulFF-F.", "frsqrteF-F.", false, "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.", } } local map_spe = { shift = 0, mask = 2047, [512] = "evaddwRRR", [514] = "evaddiwRAR~", [516] = "evsubwRRR~", [518] = "evsubiwRAR~", [520] = "evabsRR", [521] = "evnegRR", [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR", [525] = "evcntlzwRR", [526] = "evcntlswRR", [527] = "brincRRR", [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", [544] = "evsrwuRRR", [545] = "evsrwsRRR", [546] = "evsrwiuRRA", [547] = "evsrwisRRA", [548] = "evslwRRR", [550] = "evslwiRRA", [552] = "evrlwRRR", [553] = "evsplatiRS", [554] = "evrlwiRRA", [555] = "evsplatfiRS", [556] = "evmergehiRRR", [557] = "evmergeloRRR", [558] = "evmergehiloRRR", [559] = "evmergelohiRRR", [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", [564] = "evcmpeqYRR", [632] = "evselRRR", [633] = "evselRRRW", [634] = "evselRRRW", [635] = "evselRRRW", [636] = "evselRRRW", [637] = "evselRRRW", [638] = "evselRRRW", [639] = "evselRRRW", [640] = "evfsaddRRR", [641] = "evfssubRRR", [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR", [648] = "evfsmulRRR", [649] = "evfsdivRRR", [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR", [656] = "evfscfuiR-R", [657] = "evfscfsiR-R", [658] = "evfscfufR-R", [659] = "evfscfsfR-R", [660] = "evfsctuiR-R", [661] = "evfsctsiR-R", [662] = "evfsctufR-R", [663] = "evfsctsfR-R", [664] = "evfsctuizR-R", [666] = "evfsctsizR-R", [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR", [704] = "efsaddRRR", [705] = "efssubRRR", [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR", [712] = "efsmulRRR", [713] = "efsdivRRR", [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR", [719] = "efscfdR-R", [720] = "efscfuiR-R", [721] = "efscfsiR-R", [722] = "efscfufR-R", [723] = "efscfsfR-R", [724] = "efsctuiR-R", [725] = "efsctsiR-R", [726] = "efsctufR-R", [727] = "efsctsfR-R", [728] = "efsctuizR-R", [730] = "efsctsizR-R", [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR", [736] = "efdaddRRR", [737] = "efdsubRRR", [738] = "efdcfuidR-R", [739] = "efdcfsidR-R", [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR", [744] = "efdmulRRR", [745] = "efddivRRR", [746] = "efdctuidzR-R", [747] = "efdctsidzR-R", [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR", [751] = "efdcfsR-R", [752] = "efdcfuiR-R", [753] = "efdcfsiR-R", [754] = "efdcfufR-R", [755] = "efdcfsfR-R", [756] = "efdctuiR-R", [757] = "efdctsiR-R", [758] = "efdctufR-R", [759] = "efdctsfR-R", [760] = "efdctuizR-R", [762] = "efdctsizR-R", [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR", [768] = "evlddxRR0R", [769] = "evlddRR8", [770] = "evldwxRR0R", [771] = "evldwRR8", [772] = "evldhxRR0R", [773] = "evldhRR8", [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2", [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2", [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2", [784] = "evlwhexRR0R", [785] = "evlwheRR4", [788] = "evlwhouxRR0R", [789] = "evlwhouRR4", [790] = "evlwhosxRR0R", [791] = "evlwhosRR4", [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4", [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4", [800] = "evstddxRR0R", [801] = "evstddRR8", [802] = "evstdwxRR0R", [803] = "evstdwRR8", [804] = "evstdhxRR0R", [805] = "evstdhRR8", [816] = "evstwhexRR0R", [817] = "evstwheRR4", [820] = "evstwhoxRR0R", [821] = "evstwhoRR4", [824] = "evstwwexRR0R", [825] = "evstwweRR4", [828] = "evstwwoxRR0R", [829] = "evstwwoRR4", [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR", [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR", [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR", [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR", [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR", [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR", [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR", [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR", [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR", [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR", [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR", [1147] = "evmwsmfaRRR", [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR", [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR", [1220] = "evmraRR", [1222] = "evdivwsRRR", [1223] = "evdivwuRRR", [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR", [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR", [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR", [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR", [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR", [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR", [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR", [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR", [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR", [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR", [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR", [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR", [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR", [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR", [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR", [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR", [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR", [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR", [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR", [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR", [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR", [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR", [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR", [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR", [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR", [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR", [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR", [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR", } local map_pri = { [0] = false, false, "tdiARI", "twiARI", map_spe, false, false, "mulliRRI", "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI", "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I", "b_KBJ", "sc", "bKJ", map_crops, "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.", "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U", "andi.RR~U", "andis.RR~U", map_rld, map_ext, "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD", "stwRRD", "stwuRRD", "stbRRD", "stbuRRD", "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD", "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD", "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD", "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD", false, false, map_ld, map_fps, false, false, map_std, map_fpd, } ------------------------------------------------------------------------------ local map_gpr = { [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", } local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } -- Format a condition bit. local function condfmt(cond) if cond <= 3 then return map_cond[band(cond, 3)] else return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)]) end end ------------------------------------------------------------------------------ -- Output a nicely formatted line with an opcode and operands. local function putop(ctx, text, operands) local pos = ctx.pos local extra = "" if ctx.rel then local sym = ctx.symtab[ctx.rel] if sym then extra = "\t->"..sym end end if ctx.hexdump > 0 then ctx.out(format("%08x %s %-7s %s%s\n", ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) else ctx.out(format("%08x %-7s %s%s\n", ctx.addr+pos, text, concat(operands, ", "), extra)) end ctx.pos = pos + 4 end -- Fallback for unknown opcodes. local function unknown(ctx) return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) end -- Disassemble a single instruction. local function disass_ins(ctx) local pos = ctx.pos local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) local operands = {} local last = nil local rs = 21 ctx.op = op ctx.rel = nil local opat = map_pri[rshift(b0, 2)] while type(opat) ~= "string" do if not opat then return unknown(ctx) end opat = opat[band(rshift(op, opat.shift), opat.mask)] end local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)") if altname then pat = pat2 end for p in gmatch(pat, ".") do local x = nil if p == "R" then x = map_gpr[band(rshift(op, rs), 31)] rs = rs - 5 elseif p == "F" then x = "f"..band(rshift(op, rs), 31) rs = rs - 5 elseif p == "A" then x = band(rshift(op, rs), 31) rs = rs - 5 elseif p == "S" then x = arshift(lshift(op, 27-rs), 27) rs = rs - 5 elseif p == "I" then x = arshift(lshift(op, 16), 16) elseif p == "U" then x = band(op, 0xffff) elseif p == "D" or p == "E" then local disp = arshift(lshift(op, 16), 16) if p == "E" then disp = band(disp, -4) end if last == "r0" then last = "0" end operands[#operands] = format("%d(%s)", disp, last) elseif p >= "2" and p <= "8" then local disp = band(rshift(op, rs), 31) * p if last == "r0" then last = "0" end operands[#operands] = format("%d(%s)", disp, last) elseif p == "H" then x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4) rs = rs - 5 elseif p == "M" then x = band(rshift(op, rs), 31) + band(op, 0x20) elseif p == "C" then x = condfmt(band(rshift(op, rs), 31)) rs = rs - 5 elseif p == "B" then local bo = rshift(op, 21) local cond = band(rshift(op, 16), 31) local cn = "" rs = rs - 10 if band(bo, 4) == 0 then cn = band(bo, 2) == 0 and "dnz" or "dz" if band(bo, 0x10) == 0 then cn = cn..(band(bo, 8) == 0 and "f" or "t") end if band(bo, 0x10) == 0 then x = condfmt(cond) end name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") elseif band(bo, 0x10) == 0 then cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)] if cond > 3 then x = "cr"..rshift(cond, 2) end name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") end name = gsub(name, "_", cn) elseif p == "J" then x = arshift(lshift(op, 27-rs), 29-rs)*4 if band(op, 2) == 0 then x = ctx.addr + pos + x end ctx.rel = x x = "0x"..tohex(x) elseif p == "K" then if band(op, 1) ~= 0 then name = name.."l" end if band(op, 2) ~= 0 then name = name.."a" end elseif p == "X" or p == "Y" then x = band(rshift(op, rs+2), 7) if x == 0 and p == "Y" then x = nil else x = "cr"..x end rs = rs - 5 elseif p == "W" then x = "cr"..band(op, 7) elseif p == "Z" then x = band(rshift(op, rs-4), 255) rs = rs - 10 elseif p == ">" then operands[#operands] = rshift(operands[#operands], 1) elseif p == "0" then if last == "r0" then operands[#operands] = nil if altname then name = altname end end elseif p == "L" then name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w") elseif p == "." then if band(op, 1) == 1 then name = name.."." end elseif p == "N" then if op == 0x60000000 then name = "nop"; break end elseif p == "~" then local n = #operands operands[n-1], operands[n] = operands[n], operands[n-1] elseif p == "=" then local n = #operands if last == operands[n-1] then operands[n] = nil name = altname end elseif p == "%" then local n = #operands if last == operands[n-1] and last == operands[n-2] then operands[n] = nil operands[n-1] = nil name = altname end elseif p == "-" then rs = rs - 5 else assert(false) end if x then operands[#operands+1] = x; last = x end end return putop(ctx, name, operands) end ------------------------------------------------------------------------------ -- Disassemble a block of code. local function disass_block(ctx, ofs, len) if not ofs then ofs = 0 end local stop = len and ofs+len or #ctx.code stop = stop - stop % 4 ctx.pos = ofs - ofs % 4 ctx.rel = nil while ctx.pos < stop do disass_ins(ctx) end end -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). local function create(code, addr, out) local ctx = {} ctx.code = code ctx.addr = addr or 0 ctx.out = out or io.write ctx.symtab = {} ctx.disass = disass_block ctx.hexdump = 8 return ctx end -- Simple API: disassemble code (a string) at address and output via out. local function disass(code, addr, out) create(code, addr, out):disass() end -- Return register name for RID. local function regname(r) if r < 32 then return map_gpr[r] end return "f"..(r-32) end -- Public module functions. return { create = create, disass = disass, regname = regname }