dis_arm64.lua 30 KB

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