dis_x86.lua 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. ----------------------------------------------------------------------------
  2. -- LuaJIT x86/x64 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. -- This is a helper module used by the LuaJIT machine code dumper module.
  8. --
  9. -- Sending small code snippets to an external disassembler and mixing the
  10. -- output with our own stuff was too fragile. So I had to bite the bullet
  11. -- and write yet another x86 disassembler. Oh well ...
  12. --
  13. -- The output format is very similar to what ndisasm generates. But it has
  14. -- been developed independently by looking at the opcode tables from the
  15. -- Intel and AMD manuals. The supported instruction set is quite extensive
  16. -- and reflects what a current generation Intel or AMD CPU implements in
  17. -- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
  18. -- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor
  19. -- (VMX/SVM) instructions.
  20. --
  21. -- Notes:
  22. -- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
  23. -- * No attempt at optimization has been made -- it's fast enough for my needs.
  24. ------------------------------------------------------------------------------
  25. local type = type
  26. local sub, byte, format = string.sub, string.byte, string.format
  27. local match, gmatch, gsub = string.match, string.gmatch, string.gsub
  28. local lower, rep = string.lower, string.rep
  29. local bit = require("bit")
  30. local tohex = bit.tohex
  31. -- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
  32. local map_opc1_32 = {
  33. --0x
  34. [0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
  35. "orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
  36. --1x
  37. "adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
  38. "sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
  39. --2x
  40. "andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
  41. "subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
  42. --3x
  43. "xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
  44. "cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
  45. --4x
  46. "incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
  47. "decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
  48. --5x
  49. "pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR",
  50. "popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR",
  51. --6x
  52. "sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr",
  53. "fs:seg","gs:seg","o16:","a16",
  54. "pushUi","imulVrmi","pushBs","imulVrms",
  55. "insb","insVS","outsb","outsVS",
  56. --7x
  57. "joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
  58. "jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
  59. --8x
  60. "arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
  61. "testBmr","testVmr","xchgBrm","xchgVrm",
  62. "movBmr","movVmr","movBrm","movVrm",
  63. "movVmg","leaVrm","movWgm","popUm",
  64. --9x
  65. "nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
  66. "xchgVaR","xchgVaR","xchgVaR","xchgVaR",
  67. "sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait",
  68. "sz*pushfw,pushf","sz*popfw,popf","sahf","lahf",
  69. --Ax
  70. "movBao","movVao","movBoa","movVoa",
  71. "movsb","movsVS","cmpsb","cmpsVS",
  72. "testBai","testVai","stosb","stosVS",
  73. "lodsb","lodsVS","scasb","scasVS",
  74. --Bx
  75. "movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
  76. "movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
  77. --Cx
  78. "shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi",
  79. "enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
  80. --Dx
  81. "shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
  82. "fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
  83. --Ex
  84. "loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj",
  85. "inBau","inVau","outBua","outVua",
  86. "callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
  87. --Fx
  88. "lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
  89. "clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm",
  90. }
  91. assert(#map_opc1_32 == 255)
  92. -- Map for 1st opcode byte in 64 bit mode (overrides only).
  93. local map_opc1_64 = setmetatable({
  94. [0x06]=false, [0x07]=false, [0x0e]=false,
  95. [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,
  96. [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,
  97. [0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:",
  98. [0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb",
  99. [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
  100. [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
  101. [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
  102. [0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false,
  103. [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
  104. }, { __index = map_opc1_32 })
  105. -- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.
  106. -- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2
  107. local map_opc2 = {
  108. --0x
  109. [0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
  110. "invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
  111. --1x
  112. "movupsXrm|movssXrvm|movupdXrm|movsdXrvm",
  113. "movupsXmr|movssXmvr|movupdXmr|movsdXmvr",
  114. "movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
  115. "movlpsXmr||movlpdXmr",
  116. "unpcklpsXrvm||unpcklpdXrvm",
  117. "unpckhpsXrvm||unpckhpdXrvm",
  118. "movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
  119. "movhpsXmr||movhpdXmr",
  120. "$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
  121. "hintnopVm","hintnopVm","hintnopVm","hintnopVm",
  122. --2x
  123. "movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
  124. "movapsXrm||movapdXrm",
  125. "movapsXmr||movapdXmr",
  126. "cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt",
  127. "movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
  128. "cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
  129. "cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
  130. "ucomissXrm||ucomisdXrm",
  131. "comissXrm||comisdXrm",
  132. --3x
  133. "wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec",
  134. "opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil,
  135. --4x
  136. "cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
  137. "cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
  138. "cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
  139. "cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
  140. --5x
  141. "movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
  142. "rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm",
  143. "andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm",
  144. "orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm",
  145. "addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm",
  146. "cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm",
  147. "cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
  148. "subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm",
  149. "divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm",
  150. --6x
  151. "punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm",
  152. "pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm",
  153. "punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm",
  154. "||punpcklqdqXrvm","||punpckhqdqXrvm",
  155. "movPrVSm","movqMrm|movdquXrm|movdqaXrm",
  156. --7x
  157. "pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu",
  158. "pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu",
  159. "pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|",
  160. "vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
  161. nil,nil,
  162. "||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm",
  163. "movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
  164. --8x
  165. "joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
  166. "jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
  167. --9x
  168. "setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
  169. "setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
  170. --Ax
  171. "push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
  172. "push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
  173. --Bx
  174. "cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr",
  175. "$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt",
  176. "|popcntVrm","ud2Dp","bt!Vmu","btcVmr",
  177. "bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
  178. --Cx
  179. "xaddBmr","xaddVmr",
  180. "cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|",
  181. "pinsrwPrvWmu","pextrwDrPmu",
  182. "shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp",
  183. "bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
  184. --Dx
  185. "||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm",
  186. "paddqPrvm","pmullwPrvm",
  187. "|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
  188. "psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm",
  189. "paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm",
  190. --Ex
  191. "pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm",
  192. "pmulhuwPrvm","pmulhwPrvm",
  193. "|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
  194. "psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm",
  195. "paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm",
  196. --Fx
  197. "|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm",
  198. "pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$",
  199. "psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm",
  200. "paddbPrvm","paddwPrvm","padddPrvm","ud",
  201. }
  202. assert(map_opc2[255] == "ud")
  203. -- Map for three-byte opcodes. Can't wait for their next invention.
  204. local map_opc3 = {
  205. ["38"] = { -- [66] 0f 38 xx
  206. --0x
  207. [0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm",
  208. "pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm",
  209. "psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm",
  210. "||permilpsXrvm","||permilpdXrvm",nil,nil,
  211. --1x
  212. "||pblendvbXrma",nil,nil,nil,
  213. "||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm",
  214. "||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil,
  215. "pabsbPrm","pabswPrm","pabsdPrm",nil,
  216. --2x
  217. "||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
  218. "||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
  219. "||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm",
  220. "||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr",
  221. --3x
  222. "||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
  223. "||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm",
  224. "||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm",
  225. "||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm",
  226. --4x
  227. "||pmulddXrvm","||phminposuwXrm",nil,nil,
  228. nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm",
  229. --5x
  230. [0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm",
  231. [0x5a] = "||broadcasti128XrlXm",
  232. --7x
  233. [0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm",
  234. --8x
  235. [0x8c] = "||pmaskmovXrvVSm",
  236. [0x8e] = "||pmaskmovVSmXvr",
  237. --Dx
  238. [0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm",
  239. [0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm",
  240. --Fx
  241. [0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
  242. [0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv",
  243. },
  244. ["3a"] = { -- [66] 0f 3a xx
  245. --0x
  246. [0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil,
  247. "||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil,
  248. "||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu",
  249. "||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu",
  250. --1x
  251. nil,nil,nil,nil,
  252. "||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
  253. "||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil,
  254. nil,nil,nil,nil,
  255. --2x
  256. "||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil,
  257. --3x
  258. [0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru",
  259. --4x
  260. [0x40] = "||dppsXrvmu",
  261. [0x41] = "||dppdXrvmu",
  262. [0x42] = "||mpsadbwXrvmu",
  263. [0x44] = "||pclmulqdqXrvmu",
  264. [0x46] = "||perm2i128Xrvmu",
  265. [0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb",
  266. [0x4c] = "||pblendvbXrvmb",
  267. --6x
  268. [0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
  269. [0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
  270. [0xdf] = "||aeskeygenassistXrmu",
  271. --Fx
  272. [0xf0] = "||| rorxVrmu",
  273. },
  274. }
  275. -- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).
  276. local map_opcvm = {
  277. [0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff",
  278. [0xc8]="monitor",[0xc9]="mwait",
  279. [0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave",
  280. [0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga",
  281. [0xf8]="swapgs",[0xf9]="rdtscp",
  282. }
  283. -- Map for FP opcodes. And you thought stack machines are simple?
  284. local map_opcfp = {
  285. -- D8-DF 00-BF: opcodes with a memory operand.
  286. -- D8
  287. [0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
  288. "fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm",
  289. -- DA
  290. "fiaddDm","fimulDm","ficomDm","ficompDm",
  291. "fisubDm","fisubrDm","fidivDm","fidivrDm",
  292. -- DB
  293. "fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
  294. -- DC
  295. "faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
  296. -- DD
  297. "fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
  298. -- DE
  299. "fiaddWm","fimulWm","ficomWm","ficompWm",
  300. "fisubWm","fisubrWm","fidivWm","fidivrWm",
  301. -- DF
  302. "fildWm","fisttpWm","fistWm","fistpWm",
  303. "fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
  304. -- xx C0-FF: opcodes with a pseudo-register operand.
  305. -- D8
  306. "faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
  307. -- D9
  308. "fldFf","fxchFf",{"fnop"},nil,
  309. {"fchs","fabs",nil,nil,"ftst","fxam"},
  310. {"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
  311. {"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
  312. {"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
  313. -- DA
  314. "fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
  315. -- DB
  316. "fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
  317. {nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
  318. -- DC
  319. "fadd toFf","fmul toFf",nil,nil,
  320. "fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
  321. -- DD
  322. "ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
  323. -- DE
  324. "faddpFf","fmulpFf",nil,{nil,"fcompp"},
  325. "fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
  326. -- DF
  327. nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
  328. }
  329. assert(map_opcfp[126] == "fcomipFf")
  330. -- Map for opcode groups. The subkey is sp from the ModRM byte.
  331. local map_opcgroup = {
  332. arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
  333. shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
  334. testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
  335. testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
  336. incb = { "inc", "dec" },
  337. incd = { "inc", "dec", "callUmp", "$call farDmp",
  338. "jmpUmp", "$jmp farDmp", "pushUm" },
  339. sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
  340. sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt",
  341. "smsw", nil, "lmsw", "vm*$invlpg" },
  342. bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
  343. cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil,
  344. nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" },
  345. pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
  346. pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
  347. pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
  348. pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
  349. fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr",
  350. nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" },
  351. prefetch = { "prefetch", "prefetchw" },
  352. prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
  353. }
  354. ------------------------------------------------------------------------------
  355. -- Maps for register names.
  356. local map_regs = {
  357. B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
  358. "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
  359. B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
  360. "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
  361. W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
  362. "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" },
  363. D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
  364. "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" },
  365. Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
  366. "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" },
  367. M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
  368. "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
  369. X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
  370. "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
  371. Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
  372. "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" },
  373. }
  374. local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
  375. -- Maps for size names.
  376. local map_sz2n = {
  377. B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32,
  378. }
  379. local map_sz2prefix = {
  380. B = "byte", W = "word", D = "dword",
  381. Q = "qword",
  382. M = "qword", X = "xword", Y = "yword",
  383. F = "dword", G = "qword", -- No need for sizes/register names for these two.
  384. }
  385. ------------------------------------------------------------------------------
  386. -- Output a nicely formatted line with an opcode and operands.
  387. local function putop(ctx, text, operands)
  388. local code, pos, hex = ctx.code, ctx.pos, ""
  389. local hmax = ctx.hexdump
  390. if hmax > 0 then
  391. for i=ctx.start,pos-1 do
  392. hex = hex..format("%02X", byte(code, i, i))
  393. end
  394. if #hex > hmax then hex = sub(hex, 1, hmax)..". "
  395. else hex = hex..rep(" ", hmax-#hex+2) end
  396. end
  397. if operands then text = text.." "..operands end
  398. if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
  399. if ctx.a32 then text = "a32 "..text; ctx.a32 = false end
  400. if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
  401. if ctx.rex then
  402. local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
  403. (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")..
  404. (ctx.vexl and "l" or "")
  405. if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end
  406. if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "")
  407. elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end
  408. ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
  409. ctx.rex = false; ctx.vexl = false; ctx.vexv = false
  410. end
  411. if ctx.seg then
  412. local text2, n = gsub(text, "%[", "["..ctx.seg..":")
  413. if n == 0 then text = ctx.seg.." "..text else text = text2 end
  414. ctx.seg = false
  415. end
  416. if ctx.lock then text = "lock "..text; ctx.lock = false end
  417. local imm = ctx.imm
  418. if imm then
  419. local sym = ctx.symtab[imm]
  420. if sym then text = text.."\t->"..sym end
  421. end
  422. ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
  423. ctx.mrm = false
  424. ctx.vexv = false
  425. ctx.start = pos
  426. ctx.imm = nil
  427. end
  428. -- Clear all prefix flags.
  429. local function clearprefixes(ctx)
  430. ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
  431. ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
  432. ctx.rex = false; ctx.a32 = false; ctx.vexl = false
  433. end
  434. -- Fallback for incomplete opcodes at the end.
  435. local function incomplete(ctx)
  436. ctx.pos = ctx.stop+1
  437. clearprefixes(ctx)
  438. return putop(ctx, "(incomplete)")
  439. end
  440. -- Fallback for unknown opcodes.
  441. local function unknown(ctx)
  442. clearprefixes(ctx)
  443. return putop(ctx, "(unknown)")
  444. end
  445. -- Return an immediate of the specified size.
  446. local function getimm(ctx, pos, n)
  447. if pos+n-1 > ctx.stop then return incomplete(ctx) end
  448. local code = ctx.code
  449. if n == 1 then
  450. local b1 = byte(code, pos, pos)
  451. return b1
  452. elseif n == 2 then
  453. local b1, b2 = byte(code, pos, pos+1)
  454. return b1+b2*256
  455. else
  456. local b1, b2, b3, b4 = byte(code, pos, pos+3)
  457. local imm = b1+b2*256+b3*65536+b4*16777216
  458. ctx.imm = imm
  459. return imm
  460. end
  461. end
  462. -- Process pattern string and generate the operands.
  463. local function putpat(ctx, name, pat)
  464. local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
  465. local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl
  466. -- Chars used: 1DFGIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
  467. for p in gmatch(pat, ".") do
  468. local x = nil
  469. if p == "V" or p == "U" then
  470. if ctx.rexw then sz = "Q"; ctx.rexw = false
  471. elseif ctx.o16 then sz = "W"; ctx.o16 = false
  472. elseif p == "U" and ctx.x64 then sz = "Q"
  473. else sz = "D" end
  474. regs = map_regs[sz]
  475. elseif p == "T" then
  476. if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end
  477. regs = map_regs[sz]
  478. elseif p == "B" then
  479. sz = "B"
  480. regs = ctx.rex and map_regs.B64 or map_regs.B
  481. elseif match(p, "[WDQMXYFG]") then
  482. sz = p
  483. if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
  484. regs = map_regs[sz]
  485. elseif p == "P" then
  486. sz = ctx.o16 and "X" or "M"; ctx.o16 = false
  487. if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
  488. regs = map_regs[sz]
  489. elseif p == "S" then
  490. name = name..lower(sz)
  491. elseif p == "s" then
  492. local imm = getimm(ctx, pos, 1); if not imm then return end
  493. x = imm <= 127 and format("+0x%02x", imm)
  494. or format("-0x%02x", 256-imm)
  495. pos = pos+1
  496. elseif p == "u" then
  497. local imm = getimm(ctx, pos, 1); if not imm then return end
  498. x = format("0x%02x", imm)
  499. pos = pos+1
  500. elseif p == "b" then
  501. local imm = getimm(ctx, pos, 1); if not imm then return end
  502. x = regs[imm/16+1]
  503. pos = pos+1
  504. elseif p == "w" then
  505. local imm = getimm(ctx, pos, 2); if not imm then return end
  506. x = format("0x%x", imm)
  507. pos = pos+2
  508. elseif p == "o" then -- [offset]
  509. if ctx.x64 then
  510. local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
  511. local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
  512. x = format("[0x%08x%08x]", imm2, imm1)
  513. pos = pos+8
  514. else
  515. local imm = getimm(ctx, pos, 4); if not imm then return end
  516. x = format("[0x%08x]", imm)
  517. pos = pos+4
  518. end
  519. elseif p == "i" or p == "I" then
  520. local n = map_sz2n[sz]
  521. if n == 8 and ctx.x64 and p == "I" then
  522. local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
  523. local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
  524. x = format("0x%08x%08x", imm2, imm1)
  525. else
  526. if n == 8 then n = 4 end
  527. local imm = getimm(ctx, pos, n); if not imm then return end
  528. if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then
  529. imm = (0xffffffff+1)-imm
  530. x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm)
  531. else
  532. x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
  533. end
  534. end
  535. pos = pos+n
  536. elseif p == "j" then
  537. local n = map_sz2n[sz]
  538. if n == 8 then n = 4 end
  539. local imm = getimm(ctx, pos, n); if not imm then return end
  540. if sz == "B" and imm > 127 then imm = imm-256
  541. elseif imm > 2147483647 then imm = imm-4294967296 end
  542. pos = pos+n
  543. imm = imm + pos + ctx.addr
  544. if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end
  545. ctx.imm = imm
  546. if sz == "W" then
  547. x = format("word 0x%04x", imm%65536)
  548. elseif ctx.x64 then
  549. local lo = imm % 0x1000000
  550. x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
  551. else
  552. x = "0x"..tohex(imm)
  553. end
  554. elseif p == "R" then
  555. local r = byte(code, pos-1, pos-1)%8
  556. if ctx.rexb then r = r + 8; ctx.rexb = false end
  557. x = regs[r+1]
  558. elseif p == "a" then x = regs[1]
  559. elseif p == "c" then x = "cl"
  560. elseif p == "d" then x = "dx"
  561. elseif p == "1" then x = "1"
  562. else
  563. if not mode then
  564. mode = ctx.mrm
  565. if not mode then
  566. if pos > stop then return incomplete(ctx) end
  567. mode = byte(code, pos, pos)
  568. pos = pos+1
  569. end
  570. rm = mode%8; mode = (mode-rm)/8
  571. sp = mode%8; mode = (mode-sp)/8
  572. sdisp = ""
  573. if mode < 3 then
  574. if rm == 4 then
  575. if pos > stop then return incomplete(ctx) end
  576. sc = byte(code, pos, pos)
  577. pos = pos+1
  578. rm = sc%8; sc = (sc-rm)/8
  579. rx = sc%8; sc = (sc-rx)/8
  580. if ctx.rexx then rx = rx + 8; ctx.rexx = false end
  581. if rx == 4 then rx = nil end
  582. end
  583. if mode > 0 or rm == 5 then
  584. local dsz = mode
  585. if dsz ~= 1 then dsz = 4 end
  586. local disp = getimm(ctx, pos, dsz); if not disp then return end
  587. if mode == 0 then rm = nil end
  588. if rm or rx or (not sc and ctx.x64 and not ctx.a32) then
  589. if dsz == 1 and disp > 127 then
  590. sdisp = format("-0x%x", 256-disp)
  591. elseif disp >= 0 and disp <= 0x7fffffff then
  592. sdisp = format("+0x%x", disp)
  593. else
  594. sdisp = format("-0x%x", (0xffffffff+1)-disp)
  595. end
  596. else
  597. sdisp = format(ctx.x64 and not ctx.a32 and
  598. not (disp >= 0 and disp <= 0x7fffffff)
  599. and "0xffffffff%08x" or "0x%08x", disp)
  600. end
  601. pos = pos+dsz
  602. end
  603. end
  604. if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end
  605. if ctx.rexr then sp = sp + 8; ctx.rexr = false end
  606. end
  607. if p == "m" then
  608. if mode == 3 then x = regs[rm+1]
  609. else
  610. local aregs = ctx.a32 and map_regs.D or ctx.aregs
  611. local srm, srx = "", ""
  612. if rm then srm = aregs[rm+1]
  613. elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end
  614. ctx.a32 = false
  615. if rx then
  616. if rm then srm = srm.."+" end
  617. srx = aregs[rx+1]
  618. if sc > 0 then srx = srx.."*"..(2^sc) end
  619. end
  620. x = format("[%s%s%s]", srm, srx, sdisp)
  621. end
  622. if mode < 3 and
  623. (not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck.
  624. x = map_sz2prefix[sz].." "..x
  625. end
  626. elseif p == "r" then x = regs[sp+1]
  627. elseif p == "g" then x = map_segregs[sp+1]
  628. elseif p == "p" then -- Suppress prefix.
  629. elseif p == "f" then x = "st"..rm
  630. elseif p == "x" then
  631. if sp == 0 and ctx.lock and not ctx.x64 then
  632. x = "CR8"; ctx.lock = false
  633. else
  634. x = "CR"..sp
  635. end
  636. elseif p == "v" then
  637. if ctx.vexv then
  638. x = regs[ctx.vexv+1]; ctx.vexv = false
  639. end
  640. elseif p == "y" then x = "DR"..sp
  641. elseif p == "z" then x = "TR"..sp
  642. elseif p == "l" then vexl = false
  643. elseif p == "t" then
  644. else
  645. error("bad pattern `"..pat.."'")
  646. end
  647. end
  648. if x then operands = operands and operands..", "..x or x end
  649. end
  650. ctx.pos = pos
  651. return putop(ctx, name, operands)
  652. end
  653. -- Forward declaration.
  654. local map_act
  655. -- Fetch and cache MRM byte.
  656. local function getmrm(ctx)
  657. local mrm = ctx.mrm
  658. if not mrm then
  659. local pos = ctx.pos
  660. if pos > ctx.stop then return nil end
  661. mrm = byte(ctx.code, pos, pos)
  662. ctx.pos = pos+1
  663. ctx.mrm = mrm
  664. end
  665. return mrm
  666. end
  667. -- Dispatch to handler depending on pattern.
  668. local function dispatch(ctx, opat, patgrp)
  669. if not opat then return unknown(ctx) end
  670. if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
  671. local p
  672. if ctx.rep then
  673. p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)"
  674. ctx.rep = false
  675. elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false
  676. else p = "^[^%|]*" end
  677. opat = match(opat, p)
  678. if not opat then return unknown(ctx) end
  679. -- ctx.rep = false; ctx.o16 = false
  680. --XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi]
  681. --XXX remove in branches?
  682. end
  683. if match(opat, "%$") then -- reg$mem variants.
  684. local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
  685. opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)")
  686. if opat == "" then return unknown(ctx) end
  687. end
  688. if opat == "" then return unknown(ctx) end
  689. local name, pat = match(opat, "^([a-z0-9 ]*)(.*)")
  690. if pat == "" and patgrp then pat = patgrp end
  691. return map_act[sub(pat, 1, 1)](ctx, name, pat)
  692. end
  693. -- Get a pattern from an opcode map and dispatch to handler.
  694. local function dispatchmap(ctx, opcmap)
  695. local pos = ctx.pos
  696. local opat = opcmap[byte(ctx.code, pos, pos)]
  697. pos = pos + 1
  698. ctx.pos = pos
  699. return dispatch(ctx, opat)
  700. end
  701. -- Map for action codes. The key is the first char after the name.
  702. map_act = {
  703. -- Simple opcodes without operands.
  704. [""] = function(ctx, name, pat)
  705. return putop(ctx, name)
  706. end,
  707. -- Operand size chars fall right through.
  708. B = putpat, W = putpat, D = putpat, Q = putpat,
  709. V = putpat, U = putpat, T = putpat,
  710. M = putpat, X = putpat, P = putpat,
  711. F = putpat, G = putpat, Y = putpat,
  712. -- Collect prefixes.
  713. [":"] = function(ctx, name, pat)
  714. ctx[pat == ":" and name or sub(pat, 2)] = name
  715. if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.
  716. end,
  717. -- Chain to special handler specified by name.
  718. ["*"] = function(ctx, name, pat)
  719. return map_act[name](ctx, name, sub(pat, 2))
  720. end,
  721. -- Use named subtable for opcode group.
  722. ["!"] = function(ctx, name, pat)
  723. local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
  724. return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))
  725. end,
  726. -- o16,o32[,o64] variants.
  727. sz = function(ctx, name, pat)
  728. if ctx.o16 then ctx.o16 = false
  729. else
  730. pat = match(pat, ",(.*)")
  731. if ctx.rexw then
  732. local p = match(pat, ",(.*)")
  733. if p then pat = p; ctx.rexw = false end
  734. end
  735. end
  736. pat = match(pat, "^[^,]*")
  737. return dispatch(ctx, pat)
  738. end,
  739. -- Two-byte opcode dispatch.
  740. opc2 = function(ctx, name, pat)
  741. return dispatchmap(ctx, map_opc2)
  742. end,
  743. -- Three-byte opcode dispatch.
  744. opc3 = function(ctx, name, pat)
  745. return dispatchmap(ctx, map_opc3[pat])
  746. end,
  747. -- VMX/SVM dispatch.
  748. vm = function(ctx, name, pat)
  749. return dispatch(ctx, map_opcvm[ctx.mrm])
  750. end,
  751. -- Floating point opcode dispatch.
  752. fp = function(ctx, name, pat)
  753. local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
  754. local rm = mrm%8
  755. local idx = pat*8 + ((mrm-rm)/8)%8
  756. if mrm >= 192 then idx = idx + 64 end
  757. local opat = map_opcfp[idx]
  758. if type(opat) == "table" then opat = opat[rm+1] end
  759. return dispatch(ctx, opat)
  760. end,
  761. -- REX prefix.
  762. rex = function(ctx, name, pat)
  763. if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
  764. for p in gmatch(pat, ".") do ctx["rex"..p] = true end
  765. ctx.rex = "rex"
  766. end,
  767. -- VEX prefix.
  768. vex = function(ctx, name, pat)
  769. if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
  770. ctx.rex = "vex"
  771. local pos = ctx.pos
  772. if ctx.mrm then
  773. ctx.mrm = nil
  774. pos = pos-1
  775. end
  776. local b = byte(ctx.code, pos, pos)
  777. if not b then return incomplete(ctx) end
  778. pos = pos+1
  779. if b < 128 then ctx.rexr = true end
  780. local m = 1
  781. if pat == "3" then
  782. m = b%32; b = (b-m)/32
  783. local nb = b%2; b = (b-nb)/2
  784. if nb == 0 then ctx.rexb = true end
  785. local nx = b%2
  786. if nx == 0 then ctx.rexx = true end
  787. b = byte(ctx.code, pos, pos)
  788. if not b then return incomplete(ctx) end
  789. pos = pos+1
  790. if b >= 128 then ctx.rexw = true end
  791. end
  792. ctx.pos = pos
  793. local map
  794. if m == 1 then map = map_opc2
  795. elseif m == 2 then map = map_opc3["38"]
  796. elseif m == 3 then map = map_opc3["3a"]
  797. else return unknown(ctx) end
  798. local p = b%4; b = (b-p)/4
  799. if p == 1 then ctx.o16 = "o16"
  800. elseif p == 2 then ctx.rep = "rep"
  801. elseif p == 3 then ctx.rep = "repne" end
  802. local l = b%2; b = (b-l)/2
  803. if l ~= 0 then ctx.vexl = true end
  804. ctx.vexv = (-1-b)%16
  805. return dispatchmap(ctx, map)
  806. end,
  807. -- Special case for nop with REX prefix.
  808. nop = function(ctx, name, pat)
  809. return dispatch(ctx, ctx.rex and pat or "nop")
  810. end,
  811. -- Special case for 0F 77.
  812. emms = function(ctx, name, pat)
  813. if ctx.rex ~= "vex" then
  814. return putop(ctx, "emms")
  815. elseif ctx.vexl then
  816. ctx.vexl = false
  817. return putop(ctx, "zeroall")
  818. else
  819. return putop(ctx, "zeroupper")
  820. end
  821. end,
  822. }
  823. ------------------------------------------------------------------------------
  824. -- Disassemble a block of code.
  825. local function disass_block(ctx, ofs, len)
  826. if not ofs then ofs = 0 end
  827. local stop = len and ofs+len or #ctx.code
  828. ofs = ofs + 1
  829. ctx.start = ofs
  830. ctx.pos = ofs
  831. ctx.stop = stop
  832. ctx.imm = nil
  833. ctx.mrm = false
  834. clearprefixes(ctx)
  835. while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end
  836. if ctx.pos ~= ctx.start then incomplete(ctx) end
  837. end
  838. -- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
  839. local function create(code, addr, out)
  840. local ctx = {}
  841. ctx.code = code
  842. ctx.addr = (addr or 0) - 1
  843. ctx.out = out or io.write
  844. ctx.symtab = {}
  845. ctx.disass = disass_block
  846. ctx.hexdump = 16
  847. ctx.x64 = false
  848. ctx.map1 = map_opc1_32
  849. ctx.aregs = map_regs.D
  850. return ctx
  851. end
  852. local function create64(code, addr, out)
  853. local ctx = create(code, addr, out)
  854. ctx.x64 = true
  855. ctx.map1 = map_opc1_64
  856. ctx.aregs = map_regs.Q
  857. return ctx
  858. end
  859. -- Simple API: disassemble code (a string) at address and output via out.
  860. local function disass(code, addr, out)
  861. create(code, addr, out):disass()
  862. end
  863. local function disass64(code, addr, out)
  864. create64(code, addr, out):disass()
  865. end
  866. -- Return register name for RID.
  867. local function regname(r)
  868. if r < 8 then return map_regs.D[r+1] end
  869. return map_regs.X[r-7]
  870. end
  871. local function regname64(r)
  872. if r < 16 then return map_regs.Q[r+1] end
  873. return map_regs.X[r-15]
  874. end
  875. -- Public module functions.
  876. return {
  877. create = create,
  878. create64 = create64,
  879. disass = disass,
  880. disass64 = disass64,
  881. regname = regname,
  882. regname64 = regname64
  883. }