const char dis_x86_lua[] =
"----------------------------------------------------------------------------\n"
"-- LuaJIT x86/x64 disassembler module.\n"
"--\n"
"-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.\n"
"-- Released under the MIT license. See Copyright Notice in luajit.h\n"
"----------------------------------------------------------------------------\n"
"-- This is a helper module used by the LuaJIT machine code dumper module.\n"
"--\n"
"-- Sending small code snippets to an external disassembler and mixing the\n"
"-- output with our own stuff was too fragile. So I had to bite the bullet\n"
"-- and write yet another x86 disassembler. Oh well ...\n"
"--\n"
"-- The output format is very similar to what ndisasm generates. But it has\n"
"-- been developed independently by looking at the opcode tables from the\n"
"-- Intel and AMD manuals. The supported instruction set is quite extensive\n"
"-- and reflects what a current generation Intel or AMD CPU implements in\n"
"-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,\n"
"-- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor\n"
"-- (VMX/SVM) instructions.\n"
"--\n"
"-- Notes:\n"
"-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.\n"
"-- * No attempt at optimization has been made -- it's fast enough for my needs.\n"
"------------------------------------------------------------------------------\n"
"\n"
"local type = type\n"
"local sub, byte, format = string.sub, string.byte, string.format\n"
"local match, gmatch, gsub = string.match, string.gmatch, string.gsub\n"
"local lower, rep = string.lower, string.rep\n"
"local bit = require(\"bit\")\n"
"local tohex = bit.tohex\n"
"\n"
"-- Map for 1st opcode byte in 32 bit mode. Ugly\? Well ... read on.\n"
"local map_opc1_32 = {\n"
"--0x\n"
"[0]=\"addBmr\",\"addVmr\",\"addBrm\",\"addVrm\",\"addBai\",\"addVai\",\"push es\",\"pop es\",\n"
"\"orBmr\",\"orVmr\",\"orBrm\",\"orVrm\",\"orBai\",\"orVai\",\"push cs\",\"opc2*\",\n"
"--1x\n"
"\"adcBmr\",\"adcVmr\",\"adcBrm\",\"adcVrm\",\"adcBai\",\"adcVai\",\"push ss\",\"pop ss\",\n"
"\"sbbBmr\",\"sbbVmr\",\"sbbBrm\",\"sbbVrm\",\"sbbBai\",\"sbbVai\",\"push ds\",\"pop ds\",\n"
"--2x\n"
"\"andBmr\",\"andVmr\",\"andBrm\",\"andVrm\",\"andBai\",\"andVai\",\"es:seg\",\"daa\",\n"
"\"subBmr\",\"subVmr\",\"subBrm\",\"subVrm\",\"subBai\",\"subVai\",\"cs:seg\",\"das\",\n"
"--3x\n"
"\"xorBmr\",\"xorVmr\",\"xorBrm\",\"xorVrm\",\"xorBai\",\"xorVai\",\"ss:seg\",\"aaa\",\n"
"\"cmpBmr\",\"cmpVmr\",\"cmpBrm\",\"cmpVrm\",\"cmpBai\",\"cmpVai\",\"ds:seg\",\"aas\",\n"
"--4x\n"
"\"incVR\",\"incVR\",\"incVR\",\"incVR\",\"incVR\",\"incVR\",\"incVR\",\"incVR\",\n"
"\"decVR\",\"decVR\",\"decVR\",\"decVR\",\"decVR\",\"decVR\",\"decVR\",\"decVR\",\n"
"--5x\n"
"\"pushUR\",\"pushUR\",\"pushUR\",\"pushUR\",\"pushUR\",\"pushUR\",\"pushUR\",\"pushUR\",\n"
"\"popUR\",\"popUR\",\"popUR\",\"popUR\",\"popUR\",\"popUR\",\"popUR\",\"popUR\",\n"
"--6x\n"
"\"sz*pushaw,pusha\",\"sz*popaw,popa\",\"boundVrm\",\"arplWmr\",\n"
"\"fs:seg\",\"gs:seg\",\"o16:\",\"a16\",\n"
"\"pushUi\",\"imulVrmi\",\"pushBs\",\"imulVrms\",\n"
"\"insb\",\"insVS\",\"outsb\",\"outsVS\",\n"
"--7x\n"
"\"joBj\",\"jnoBj\",\"jbBj\",\"jnbBj\",\"jzBj\",\"jnzBj\",\"jbeBj\",\"jaBj\",\n"
"\"jsBj\",\"jnsBj\",\"jpeBj\",\"jpoBj\",\"jlBj\",\"jgeBj\",\"jleBj\",\"jgBj\",\n"
"--8x\n"
"\"arith!Bmi\",\"arith!Vmi\",\"arith!Bmi\",\"arith!Vms\",\n"
"\"testBmr\",\"testVmr\",\"xchgBrm\",\"xchgVrm\",\n"
"\"movBmr\",\"movVmr\",\"movBrm\",\"movVrm\",\n"
"\"movVmg\",\"leaVrm\",\"movWgm\",\"popUm\",\n"
"--9x\n"
"\"nop*xchgVaR|pause|xchgWaR|repne nop\",\"xchgVaR\",\"xchgVaR\",\"xchgVaR\",\n"
"\"xchgVaR\",\"xchgVaR\",\"xchgVaR\",\"xchgVaR\",\n"
"\"sz*cbw,cwde,cdqe\",\"sz*cwd,cdq,cqo\",\"call farViw\",\"wait\",\n"
"\"sz*pushfw,pushf\",\"sz*popfw,popf\",\"sahf\",\"lahf\",\n"
"--Ax\n"
"\"movBao\",\"movVao\",\"movBoa\",\"movVoa\",\n"
"\"movsb\",\"movsVS\",\"cmpsb\",\"cmpsVS\",\n"
"\"testBai\",\"testVai\",\"stosb\",\"stosVS\",\n"
"\"lodsb\",\"lodsVS\",\"scasb\",\"scasVS\",\n"
"--Bx\n"
"\"movBRi\",\"movBRi\",\"movBRi\",\"movBRi\",\"movBRi\",\"movBRi\",\"movBRi\",\"movBRi\",\n"
"\"movVRI\",\"movVRI\",\"movVRI\",\"movVRI\",\"movVRI\",\"movVRI\",\"movVRI\",\"movVRI\",\n"
"--Cx\n"
"\"shift!Bmu\",\"shift!Vmu\",\"retBw\",\"ret\",\"vex*3$lesVrm\",\"vex*2$ldsVrm\",\"movBmi\",\"movVmi\",\n"
"\"enterBwu\",\"leave\",\"retfBw\",\"retf\",\"int3\",\"intBu\",\"into\",\"iretVS\",\n"
"--Dx\n"
"\"shift!Bm1\",\"shift!Vm1\",\"shift!Bmc\",\"shift!Vmc\",\"aamBu\",\"aadBu\",\"salc\",\"xlatb\",\n"
"\"fp*0\",\"fp*1\",\"fp*2\",\"fp*3\",\"fp*4\",\"fp*5\",\"fp*6\",\"fp*7\",\n"
"--Ex\n"
"\"loopneBj\",\"loopeBj\",\"loopBj\",\"sz*jcxzBj,jecxzBj,jrcxzBj\",\n"
"\"inBau\",\"inVau\",\"outBua\",\"outVua\",\n"
"\"callVj\",\"jmpVj\",\"jmp farViw\",\"jmpBj\",\"inBad\",\"inVad\",\"outBda\",\"outVda\",\n"
"--Fx\n"
"\"lock:\",\"int1\",\"repne:rep\",\"rep:\",\"hlt\",\"cmc\",\"testb!Bm\",\"testv!Vm\",\n"
"\"clc\",\"stc\",\"cli\",\"sti\",\"cld\",\"std\",\"incb!Bm\",\"incd!Vm\",\n"
"}\n"
"assert(#map_opc1_32 == 255)\n"
"\n"
"-- Map for 1st opcode byte in 64 bit mode (overrides only).\n"
"local map_opc1_64 = setmetatable({\n"
"  [0x06]=false, [0x07]=false, [0x0e]=false,\n"
"  [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,\n"
"  [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,\n"
"  [0x60]=false, [0x61]=false, [0x62]=false, [0x63]=\"movsxdVrDmt\", [0x67]=\"a32:\",\n"
"  [0x40]=\"rex*\",   [0x41]=\"rex*b\",   [0x42]=\"rex*x\",   [0x43]=\"rex*xb\",\n"
"  [0x44]=\"rex*r\",  [0x45]=\"rex*rb\",  [0x46]=\"rex*rx\",  [0x47]=\"rex*rxb\",\n"
"  [0x48]=\"rex*w\",  [0x49]=\"rex*wb\",  [0x4a]=\"rex*wx\",  [0x4b]=\"rex*wxb\",\n"
"  [0x4c]=\"rex*wr\", [0x4d]=\"rex*wrb\", [0x4e]=\"rex*wrx\", [0x4f]=\"rex*wrxb\",\n"
"  [0x82]=false, [0x9a]=false, [0xc4]=\"vex*3\", [0xc5]=\"vex*2\", [0xce]=false,\n"
"  [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,\n"
"}, { __index = map_opc1_32 })\n"
"\n"
"-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.\n"
"-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2\n"
"local map_opc2 = {\n"
"--0x\n"
"[0]=\"sldt!Dmp\",\"sgdt!Ump\",\"larVrm\",\"lslVrm\",nil,\"syscall\",\"clts\",\"sysret\",\n"
"\"invd\",\"wbinvd\",nil,\"ud1\",nil,\"$prefetch!Bm\",\"femms\",\"3dnowMrmu\",\n"
"--1x\n"
"\"movupsXrm|movssXrvm|movupdXrm|movsdXrvm\",\n"
"\"movupsXmr|movssXmvr|movupdXmr|movsdXmvr\",\n"
"\"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm\",\n"
"\"movlpsXmr||movlpdXmr\",\n"
"\"unpcklpsXrvm||unpcklpdXrvm\",\n"
"\"unpckhpsXrvm||unpckhpdXrvm\",\n"
"\"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm\",\n"
"\"movhpsXmr||movhpdXmr\",\n"
"\"$prefetcht!Bm\",\"hintnopVm\",\"hintnopVm\",\"hintnopVm\",\n"
"\"hintnopVm\",\"hintnopVm\",\"hintnopVm\",\"hintnopVm\",\n"
"--2x\n"
"\"movUmx$\",\"movUmy$\",\"movUxm$\",\"movUym$\",\"movUmz$\",nil,\"movUzm$\",nil,\n"
"\"movapsXrm||movapdXrm\",\n"
"\"movapsXmr||movapdXmr\",\n"
"\"cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt\",\n"
"\"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr\",\n"
"\"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm\",\n"
"\"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm\",\n"
"\"ucomissXrm||ucomisdXrm\",\n"
"\"comissXrm||comisdXrm\",\n"
"--3x\n"
"\"wrmsr\",\"rdtsc\",\"rdmsr\",\"rdpmc\",\"sysenter\",\"sysexit\",nil,\"getsec\",\n"
"\"opc3*38\",nil,\"opc3*3a\",nil,nil,nil,nil,nil,\n"
"--4x\n"
"\"cmovoVrm\",\"cmovnoVrm\",\"cmovbVrm\",\"cmovnbVrm\",\n"
"\"cmovzVrm\",\"cmovnzVrm\",\"cmovbeVrm\",\"cmovaVrm\",\n"
"\"cmovsVrm\",\"cmovnsVrm\",\"cmovpeVrm\",\"cmovpoVrm\",\n"
"\"cmovlVrm\",\"cmovgeVrm\",\"cmovleVrm\",\"cmovgVrm\",\n"
"--5x\n"
"\"movmskpsVrXm$||movmskpdVrXm$\",\"sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm\",\n"
"\"rsqrtpsXrm|rsqrtssXrvm\",\"rcppsXrm|rcpssXrvm\",\n"
"\"andpsXrvm||andpdXrvm\",\"andnpsXrvm||andnpdXrvm\",\n"
"\"orpsXrvm||orpdXrvm\",\"xorpsXrvm||xorpdXrvm\",\n"
"\"addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm\",\"mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm\",\n"
"\"cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm\",\n"
"\"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm\",\n"
"\"subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm\",\"minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm\",\n"
"\"divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm\",\"maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm\",\n"
"--6x\n"
"\"punpcklbwPrvm\",\"punpcklwdPrvm\",\"punpckldqPrvm\",\"packsswbPrvm\",\n"
"\"pcmpgtbPrvm\",\"pcmpgtwPrvm\",\"pcmpgtdPrvm\",\"packuswbPrvm\",\n"
"\"punpckhbwPrvm\",\"punpckhwdPrvm\",\"punpckhdqPrvm\",\"packssdwPrvm\",\n"
"\"||punpcklqdqXrvm\",\"||punpckhqdqXrvm\",\n"
"\"movPrVSm\",\"movqMrm|movdquXrm|movdqaXrm\",\n"
"--7x\n"
"\"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu\",\"pshiftw!Pvmu\",\n"
"\"pshiftd!Pvmu\",\"pshiftq!Mvmu||pshiftdq!Xvmu\",\n"
"\"pcmpeqbPrvm\",\"pcmpeqwPrvm\",\"pcmpeqdPrvm\",\"emms*|\",\n"
"\"vmreadUmr||extrqXmuu$|insertqXrmuu$\",\"vmwriteUrm||extrqXrm$|insertqXrm$\",\n"
"nil,nil,\n"
"\"||haddpdXrvm|haddpsXrvm\",\"||hsubpdXrvm|hsubpsXrvm\",\n"
"\"movVSmMr|movqXrm|movVSmXr\",\"movqMmr|movdquXmr|movdqaXmr\",\n"
"--8x\n"
"\"joVj\",\"jnoVj\",\"jbVj\",\"jnbVj\",\"jzVj\",\"jnzVj\",\"jbeVj\",\"jaVj\",\n"
"\"jsVj\",\"jnsVj\",\"jpeVj\",\"jpoVj\",\"jlVj\",\"jgeVj\",\"jleVj\",\"jgVj\",\n"
"--9x\n"
"\"setoBm\",\"setnoBm\",\"setbBm\",\"setnbBm\",\"setzBm\",\"setnzBm\",\"setbeBm\",\"setaBm\",\n"
"\"setsBm\",\"setnsBm\",\"setpeBm\",\"setpoBm\",\"setlBm\",\"setgeBm\",\"setleBm\",\"setgBm\",\n"
"--Ax\n"
"\"push fs\",\"pop fs\",\"cpuid\",\"btVmr\",\"shldVmru\",\"shldVmrc\",nil,nil,\n"
"\"push gs\",\"pop gs\",\"rsm\",\"btsVmr\",\"shrdVmru\",\"shrdVmrc\",\"fxsave!Dmp\",\"imulVrm\",\n"
"--Bx\n"
"\"cmpxchgBmr\",\"cmpxchgVmr\",\"$lssVrm\",\"btrVmr\",\n"
"\"$lfsVrm\",\"$lgsVrm\",\"movzxVrBmt\",\"movzxVrWmt\",\n"
"\"|popcntVrm\",\"ud2Dp\",\"bt!Vmu\",\"btcVmr\",\n"
"\"bsfVrm\",\"bsrVrm|lzcntVrm|bsrWrm\",\"movsxVrBmt\",\"movsxVrWmt\",\n"
"--Cx\n"
"\"xaddBmr\",\"xaddVmr\",\n"
"\"cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu\",\"$movntiVmr|\",\n"
"\"pinsrwPrvWmu\",\"pextrwDrPmu\",\n"
"\"shufpsXrvmu||shufpdXrvmu\",\"$cmpxchg!Qmp\",\n"
"\"bswapVR\",\"bswapVR\",\"bswapVR\",\"bswapVR\",\"bswapVR\",\"bswapVR\",\"bswapVR\",\"bswapVR\",\n"
"--Dx\n"
"\"||addsubpdXrvm|addsubpsXrvm\",\"psrlwPrvm\",\"psrldPrvm\",\"psrlqPrvm\",\n"
"\"paddqPrvm\",\"pmullwPrvm\",\n"
"\"|movq2dqXrMm|movqXmr|movdq2qMrXm$\",\"pmovmskbVrMm||pmovmskbVrXm\",\n"
"\"psubusbPrvm\",\"psubuswPrvm\",\"pminubPrvm\",\"pandPrvm\",\n"
"\"paddusbPrvm\",\"padduswPrvm\",\"pmaxubPrvm\",\"pandnPrvm\",\n"
"--Ex\n"
"\"pavgbPrvm\",\"psrawPrvm\",\"psradPrvm\",\"pavgwPrvm\",\n"
"\"pmulhuwPrvm\",\"pmulhwPrvm\",\n"
"\"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm\",\"$movntqMmr||$movntdqXmr\",\n"
"\"psubsbPrvm\",\"psubswPrvm\",\"pminswPrvm\",\"porPrvm\",\n"
"\"paddsbPrvm\",\"paddswPrvm\",\"pmaxswPrvm\",\"pxorPrvm\",\n"
"--Fx\n"
"\"|||lddquXrm\",\"psllwPrvm\",\"pslldPrvm\",\"psllqPrvm\",\n"
"\"pmuludqPrvm\",\"pmaddwdPrvm\",\"psadbwPrvm\",\"maskmovqMrm||maskmovdquXrm$\",\n"
"\"psubbPrvm\",\"psubwPrvm\",\"psubdPrvm\",\"psubqPrvm\",\n"
"\"paddbPrvm\",\"paddwPrvm\",\"padddPrvm\",\"ud\",\n"
"}\n"
"assert(map_opc2[255] == \"ud\")\n"
"\n"
"-- Map for three-byte opcodes. Can't wait for their next invention.\n"
"local map_opc3 = {\n"
"[\"38\"] = { -- [66] 0f 38 xx\n"
"--0x\n"
"[0]=\"pshufbPrvm\",\"phaddwPrvm\",\"phadddPrvm\",\"phaddswPrvm\",\n"
"\"pmaddubswPrvm\",\"phsubwPrvm\",\"phsubdPrvm\",\"phsubswPrvm\",\n"
"\"psignbPrvm\",\"psignwPrvm\",\"psigndPrvm\",\"pmulhrswPrvm\",\n"
"\"||permilpsXrvm\",\"||permilpdXrvm\",nil,nil,\n"
"--1x\n"
"\"||pblendvbXrma\",nil,nil,nil,\n"
"\"||blendvpsXrma\",\"||blendvpdXrma\",\"||permpsXrvm\",\"||ptestXrm\",\n"
"\"||broadcastssXrm\",\"||broadcastsdXrm\",\"||broadcastf128XrlXm\",nil,\n"
"\"pabsbPrm\",\"pabswPrm\",\"pabsdPrm\",nil,\n"
"--2x\n"
"\"||pmovsxbwXrm\",\"||pmovsxbdXrm\",\"||pmovsxbqXrm\",\"||pmovsxwdXrm\",\n"
"\"||pmovsxwqXrm\",\"||pmovsxdqXrm\",nil,nil,\n"
"\"||pmuldqXrvm\",\"||pcmpeqqXrvm\",\"||$movntdqaXrm\",\"||packusdwXrvm\",\n"
"\"||maskmovpsXrvm\",\"||maskmovpdXrvm\",\"||maskmovpsXmvr\",\"||maskmovpdXmvr\",\n"
"--3x\n"
"\"||pmovzxbwXrm\",\"||pmovzxbdXrm\",\"||pmovzxbqXrm\",\"||pmovzxwdXrm\",\n"
"\"||pmovzxwqXrm\",\"||pmovzxdqXrm\",\"||permdXrvm\",\"||pcmpgtqXrvm\",\n"
"\"||pminsbXrvm\",\"||pminsdXrvm\",\"||pminuwXrvm\",\"||pminudXrvm\",\n"
"\"||pmaxsbXrvm\",\"||pmaxsdXrvm\",\"||pmaxuwXrvm\",\"||pmaxudXrvm\",\n"
"--4x\n"
"\"||pmulddXrvm\",\"||phminposuwXrm\",nil,nil,\n"
"nil,\"||psrlvVSXrvm\",\"||psravdXrvm\",\"||psllvVSXrvm\",\n"
"--5x\n"
"[0x58] = \"||pbroadcastdXrlXm\",[0x59] = \"||pbroadcastqXrlXm\",\n"
"[0x5a] = \"||broadcasti128XrlXm\",\n"
"--7x\n"
"[0x78] = \"||pbroadcastbXrlXm\",[0x79] = \"||pbroadcastwXrlXm\",\n"
"--8x\n"
"[0x8c] = \"||pmaskmovXrvVSm\",\n"
"[0x8e] = \"||pmaskmovVSmXvr\",\n"
"--Dx\n"
"[0xdc] = \"||aesencXrvm\", [0xdd] = \"||aesenclastXrvm\",\n"
"[0xde] = \"||aesdecXrvm\", [0xdf] = \"||aesdeclastXrvm\",\n"
"--Fx\n"
"[0xf0] = \"|||crc32TrBmt\",[0xf1] = \"|||crc32TrVmt\",\n"
"[0xf7] = \"| sarxVrmv| shlxVrmv| shrxVrmv\",\n"
"},\n"
"\n"
"[\"3a\"] = { -- [66] 0f 3a xx\n"
"--0x\n"
"[0x00]=\"||permqXrmu\",\"||permpdXrmu\",\"||pblenddXrvmu\",nil,\n"
"\"||permilpsXrmu\",\"||permilpdXrmu\",\"||perm2f128Xrvmu\",nil,\n"
"\"||roundpsXrmu\",\"||roundpdXrmu\",\"||roundssXrvmu\",\"||roundsdXrvmu\",\n"
"\"||blendpsXrvmu\",\"||blendpdXrvmu\",\"||pblendwXrvmu\",\"palignrPrvmu\",\n"
"--1x\n"
"nil,nil,nil,nil,\n"
"\"||pextrbVmXru\",\"||pextrwVmXru\",\"||pextrVmSXru\",\"||extractpsVmXru\",\n"
"\"||insertf128XrvlXmu\",\"||extractf128XlXmYru\",nil,nil,\n"
"nil,nil,nil,nil,\n"
"--2x\n"
"\"||pinsrbXrvVmu\",\"||insertpsXrvmu\",\"||pinsrXrvVmuS\",nil,\n"
"--3x\n"
"[0x38] = \"||inserti128Xrvmu\",[0x39] = \"||extracti128XlXmYru\",\n"
"--4x\n"
"[0x40] = \"||dppsXrvmu\",\n"
"[0x41] = \"||dppdXrvmu\",\n"
"[0x42] = \"||mpsadbwXrvmu\",\n"
"[0x44] = \"||pclmulqdqXrvmu\",\n"
"[0x46] = \"||perm2i128Xrvmu\",\n"
"[0x4a] = \"||blendvpsXrvmb\",[0x4b] = \"||blendvpdXrvmb\",\n"
"[0x4c] = \"||pblendvbXrvmb\",\n"
"--6x\n"
"[0x60] = \"||pcmpestrmXrmu\",[0x61] = \"||pcmpestriXrmu\",\n"
"[0x62] = \"||pcmpistrmXrmu\",[0x63] = \"||pcmpistriXrmu\",\n"
"[0xdf] = \"||aeskeygenassistXrmu\",\n"
"--Fx\n"
"[0xf0] = \"||| rorxVrmu\",\n"
"},\n"
"}\n"
"\n"
"-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).\n"
"local map_opcvm = {\n"
"[0xc1]=\"vmcall\",[0xc2]=\"vmlaunch\",[0xc3]=\"vmresume\",[0xc4]=\"vmxoff\",\n"
"[0xc8]=\"monitor\",[0xc9]=\"mwait\",\n"
"[0xd8]=\"vmrun\",[0xd9]=\"vmmcall\",[0xda]=\"vmload\",[0xdb]=\"vmsave\",\n"
"[0xdc]=\"stgi\",[0xdd]=\"clgi\",[0xde]=\"skinit\",[0xdf]=\"invlpga\",\n"
"[0xf8]=\"swapgs\",[0xf9]=\"rdtscp\",\n"
"}\n"
"\n"
"-- Map for FP opcodes. And you thought stack machines are simple\?\n"
"local map_opcfp = {\n"
"-- D8-DF 00-BF: opcodes with a memory operand.\n"
"-- D8\n"
"[0]=\"faddFm\",\"fmulFm\",\"fcomFm\",\"fcompFm\",\"fsubFm\",\"fsubrFm\",\"fdivFm\",\"fdivrFm\",\n"
"\"fldFm\",nil,\"fstFm\",\"fstpFm\",\"fldenvVm\",\"fldcwWm\",\"fnstenvVm\",\"fnstcwWm\",\n"
"-- DA\n"
"\"fiaddDm\",\"fimulDm\",\"ficomDm\",\"ficompDm\",\n"
"\"fisubDm\",\"fisubrDm\",\"fidivDm\",\"fidivrDm\",\n"
"-- DB\n"
"\"fildDm\",\"fisttpDm\",\"fistDm\",\"fistpDm\",nil,\"fld twordFmp\",nil,\"fstp twordFmp\",\n"
"-- DC\n"
"\"faddGm\",\"fmulGm\",\"fcomGm\",\"fcompGm\",\"fsubGm\",\"fsubrGm\",\"fdivGm\",\"fdivrGm\",\n"
"-- DD\n"
"\"fldGm\",\"fisttpQm\",\"fstGm\",\"fstpGm\",\"frstorDmp\",nil,\"fnsaveDmp\",\"fnstswWm\",\n"
"-- DE\n"
"\"fiaddWm\",\"fimulWm\",\"ficomWm\",\"ficompWm\",\n"
"\"fisubWm\",\"fisubrWm\",\"fidivWm\",\"fidivrWm\",\n"
"-- DF\n"
"\"fildWm\",\"fisttpWm\",\"fistWm\",\"fistpWm\",\n"
"\"fbld twordFmp\",\"fildQm\",\"fbstp twordFmp\",\"fistpQm\",\n"
"-- xx C0-FF: opcodes with a pseudo-register operand.\n"
"-- D8\n"
"\"faddFf\",\"fmulFf\",\"fcomFf\",\"fcompFf\",\"fsubFf\",\"fsubrFf\",\"fdivFf\",\"fdivrFf\",\n"
"-- D9\n"
"\"fldFf\",\"fxchFf\",{\"fnop\"},nil,\n"
"{\"fchs\",\"fabs\",nil,nil,\"ftst\",\"fxam\"},\n"
"{\"fld1\",\"fldl2t\",\"fldl2e\",\"fldpi\",\"fldlg2\",\"fldln2\",\"fldz\"},\n"
"{\"f2xm1\",\"fyl2x\",\"fptan\",\"fpatan\",\"fxtract\",\"fprem1\",\"fdecstp\",\"fincstp\"},\n"
"{\"fprem\",\"fyl2xp1\",\"fsqrt\",\"fsincos\",\"frndint\",\"fscale\",\"fsin\",\"fcos\"},\n"
"-- DA\n"
"\"fcmovbFf\",\"fcmoveFf\",\"fcmovbeFf\",\"fcmovuFf\",nil,{nil,\"fucompp\"},nil,nil,\n"
"-- DB\n"
"\"fcmovnbFf\",\"fcmovneFf\",\"fcmovnbeFf\",\"fcmovnuFf\",\n"
"{nil,nil,\"fnclex\",\"fninit\"},\"fucomiFf\",\"fcomiFf\",nil,\n"
"-- DC\n"
"\"fadd toFf\",\"fmul toFf\",nil,nil,\n"
"\"fsub toFf\",\"fsubr toFf\",\"fdivr toFf\",\"fdiv toFf\",\n"
"-- DD\n"
"\"ffreeFf\",nil,\"fstFf\",\"fstpFf\",\"fucomFf\",\"fucompFf\",nil,nil,\n"
"-- DE\n"
"\"faddpFf\",\"fmulpFf\",nil,{nil,\"fcompp\"},\n"
"\"fsubrpFf\",\"fsubpFf\",\"fdivrpFf\",\"fdivpFf\",\n"
"-- DF\n"
"nil,nil,nil,nil,{\"fnstsw ax\"},\"fucomipFf\",\"fcomipFf\",nil,\n"
"}\n"
"assert(map_opcfp[126] == \"fcomipFf\")\n"
"\n"
"-- Map for opcode groups. The subkey is sp from the ModRM byte.\n"
"local map_opcgroup = {\n"
"  arith = { \"add\", \"or\", \"adc\", \"sbb\", \"and\", \"sub\", \"xor\", \"cmp\" },\n"
"  shift = { \"rol\", \"ror\", \"rcl\", \"rcr\", \"shl\", \"shr\", \"sal\", \"sar\" },\n"
"  testb = { \"testBmi\", \"testBmi\", \"not\", \"neg\", \"mul\", \"imul\", \"div\", \"idiv\" },\n"
"  testv = { \"testVmi\", \"testVmi\", \"not\", \"neg\", \"mul\", \"imul\", \"div\", \"idiv\" },\n"
"  incb = { \"inc\", \"dec\" },\n"
"  incd = { \"inc\", \"dec\", \"callUmp\", \"$call farDmp\",\n"
"\t   \"jmpUmp\", \"$jmp farDmp\", \"pushUm\" },\n"
"  sldt = { \"sldt\", \"str\", \"lldt\", \"ltr\", \"verr\", \"verw\" },\n"
"  sgdt = { \"vm*$sgdt\", \"vm*$sidt\", \"$lgdt\", \"vm*$lidt\",\n"
"\t   \"smsw\", nil, \"lmsw\", \"vm*$invlpg\" },\n"
"  bt = { nil, nil, nil, nil, \"bt\", \"bts\", \"btr\", \"btc\" },\n"
"  cmpxchg = { nil, \"sz*,cmpxchg8bQmp,cmpxchg16bXmp\", nil, nil,\n"
"\t      nil, nil, \"vmptrld|vmxon|vmclear\", \"vmptrst\" },\n"
"  pshiftw = { nil, nil, \"psrlw\", nil, \"psraw\", nil, \"psllw\" },\n"
"  pshiftd = { nil, nil, \"psrld\", nil, \"psrad\", nil, \"pslld\" },\n"
"  pshiftq = { nil, nil, \"psrlq\", nil, nil, nil, \"psllq\" },\n"
"  pshiftdq = { nil, nil, \"psrlq\", \"psrldq\", nil, nil, \"psllq\", \"pslldq\" },\n"
"  fxsave = { \"$fxsave\", \"$fxrstor\", \"$ldmxcsr\", \"$stmxcsr\",\n"
"\t     nil, \"lfenceDp$\", \"mfenceDp$\", \"sfenceDp$clflush\" },\n"
"  prefetch = { \"prefetch\", \"prefetchw\" },\n"
"  prefetcht = { \"prefetchnta\", \"prefetcht0\", \"prefetcht1\", \"prefetcht2\" },\n"
"}\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Maps for register names.\n"
"local map_regs = {\n"
"  B = { \"al\", \"cl\", \"dl\", \"bl\", \"ah\", \"ch\", \"dh\", \"bh\",\n"
"\t\"r8b\", \"r9b\", \"r10b\", \"r11b\", \"r12b\", \"r13b\", \"r14b\", \"r15b\" },\n"
"  B64 = { \"al\", \"cl\", \"dl\", \"bl\", \"spl\", \"bpl\", \"sil\", \"dil\",\n"
"\t  \"r8b\", \"r9b\", \"r10b\", \"r11b\", \"r12b\", \"r13b\", \"r14b\", \"r15b\" },\n"
"  W = { \"ax\", \"cx\", \"dx\", \"bx\", \"sp\", \"bp\", \"si\", \"di\",\n"
"\t\"r8w\", \"r9w\", \"r10w\", \"r11w\", \"r12w\", \"r13w\", \"r14w\", \"r15w\" },\n"
"  D = { \"eax\", \"ecx\", \"edx\", \"ebx\", \"esp\", \"ebp\", \"esi\", \"edi\",\n"
"\t\"r8d\", \"r9d\", \"r10d\", \"r11d\", \"r12d\", \"r13d\", \"r14d\", \"r15d\" },\n"
"  Q = { \"rax\", \"rcx\", \"rdx\", \"rbx\", \"rsp\", \"rbp\", \"rsi\", \"rdi\",\n"
"\t\"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r13\", \"r14\", \"r15\" },\n"
"  M = { \"mm0\", \"mm1\", \"mm2\", \"mm3\", \"mm4\", \"mm5\", \"mm6\", \"mm7\",\n"
"\t\"mm0\", \"mm1\", \"mm2\", \"mm3\", \"mm4\", \"mm5\", \"mm6\", \"mm7\" }, -- No x64 ext!\n"
"  X = { \"xmm0\", \"xmm1\", \"xmm2\", \"xmm3\", \"xmm4\", \"xmm5\", \"xmm6\", \"xmm7\",\n"
"\t\"xmm8\", \"xmm9\", \"xmm10\", \"xmm11\", \"xmm12\", \"xmm13\", \"xmm14\", \"xmm15\" },\n"
"  Y = { \"ymm0\", \"ymm1\", \"ymm2\", \"ymm3\", \"ymm4\", \"ymm5\", \"ymm6\", \"ymm7\",\n"
"\t\"ymm8\", \"ymm9\", \"ymm10\", \"ymm11\", \"ymm12\", \"ymm13\", \"ymm14\", \"ymm15\" },\n"
"}\n"
"local map_segregs = { \"es\", \"cs\", \"ss\", \"ds\", \"fs\", \"gs\", \"segr6\", \"segr7\" }\n"
"\n"
"-- Maps for size names.\n"
"local map_sz2n = {\n"
"  B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32,\n"
"}\n"
"local map_sz2prefix = {\n"
"  B = \"byte\", W = \"word\", D = \"dword\",\n"
"  Q = \"qword\",\n"
"  M = \"qword\", X = \"xword\", Y = \"yword\",\n"
"  F = \"dword\", G = \"qword\", -- No need for sizes/register names for these two.\n"
"}\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Output a nicely formatted line with an opcode and operands.\n"
"local function putop(ctx, text, operands)\n"
"  local code, pos, hex = ctx.code, ctx.pos, \"\"\n"
"  local hmax = ctx.hexdump\n"
"  if hmax > 0 then\n"
"    for i=ctx.start,pos-1 do\n"
"      hex = hex..format(\"%02X\", byte(code, i, i))\n"
"    end\n"
"    if #hex > hmax then hex = sub(hex, 1, hmax)..\". \"\n"
"    else hex = hex..rep(\" \", hmax-#hex+2) end\n"
"  end\n"
"  if operands then text = text..\" \"..operands end\n"
"  if ctx.o16 then text = \"o16 \"..text; ctx.o16 = false end\n"
"  if ctx.a32 then text = \"a32 \"..text; ctx.a32 = false end\n"
"  if ctx.rep then text = ctx.rep..\" \"..text; ctx.rep = false end\n"
"  if ctx.rex then\n"
"    local t = (ctx.rexw and \"w\" or \"\")..(ctx.rexr and \"r\" or \"\")..\n"
"\t      (ctx.rexx and \"x\" or \"\")..(ctx.rexb and \"b\" or \"\")..\n"
"\t      (ctx.vexl and \"l\" or \"\")\n"
"    if ctx.vexv and ctx.vexv ~= 0 then t = t..\"v\"..ctx.vexv end\n"
"    if t ~= \"\" then text = ctx.rex..\".\"..t..\" \"..gsub(text, \"^ \", \"\")\n"
"    elseif ctx.rex == \"vex\" then text = gsub(\"v\"..text, \"^v \", \"\") end\n"
"    ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false\n"
"    ctx.rex = false; ctx.vexl = false; ctx.vexv = false\n"
"  end\n"
"  if ctx.seg then\n"
"    local text2, n = gsub(text, \"%[\", \"[\"..ctx.seg..\":\")\n"
"    if n == 0 then text = ctx.seg..\" \"..text else text = text2 end\n"
"    ctx.seg = false\n"
"  end\n"
"  if ctx.lock then text = \"lock \"..text; ctx.lock = false end\n"
"  local imm = ctx.imm\n"
"  if imm then\n"
"    local sym = ctx.symtab[imm]\n"
"    if sym then text = text..\"\\t->\"..sym end\n"
"  end\n"
"  ctx.out(format(\"%08x  %s%s\\n\", ctx.addr+ctx.start, hex, text))\n"
"  ctx.mrm = false\n"
"  ctx.vexv = false\n"
"  ctx.start = pos\n"
"  ctx.imm = nil\n"
"end\n"
"\n"
"-- Clear all prefix flags.\n"
"local function clearprefixes(ctx)\n"
"  ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false\n"
"  ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false\n"
"  ctx.rex = false; ctx.a32 = false; ctx.vexl = false\n"
"end\n"
"\n"
"-- Fallback for incomplete opcodes at the end.\n"
"local function incomplete(ctx)\n"
"  ctx.pos = ctx.stop+1\n"
"  clearprefixes(ctx)\n"
"  return putop(ctx, \"(incomplete)\")\n"
"end\n"
"\n"
"-- Fallback for unknown opcodes.\n"
"local function unknown(ctx)\n"
"  clearprefixes(ctx)\n"
"  return putop(ctx, \"(unknown)\")\n"
"end\n"
"\n"
"-- Return an immediate of the specified size.\n"
"local function getimm(ctx, pos, n)\n"
"  if pos+n-1 > ctx.stop then return incomplete(ctx) end\n"
"  local code = ctx.code\n"
"  if n == 1 then\n"
"    local b1 = byte(code, pos, pos)\n"
"    return b1\n"
"  elseif n == 2 then\n"
"    local b1, b2 = byte(code, pos, pos+1)\n"
"    return b1+b2*256\n"
"  else\n"
"    local b1, b2, b3, b4 = byte(code, pos, pos+3)\n"
"    local imm = b1+b2*256+b3*65536+b4*16777216\n"
"    ctx.imm = imm\n"
"    return imm\n"
"  end\n"
"end\n"
"\n"
"-- Process pattern string and generate the operands.\n"
"local function putpat(ctx, name, pat)\n"
"  local operands, regs, sz, mode, sp, rm, sc, rx, sdisp\n"
"  local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl\n"
"\n"
"  -- Chars used: 1DFGIMPQRSTUVWXYabcdfgijlmoprstuvwxyz\n"
"  for p in gmatch(pat, \".\") do\n"
"    local x = nil\n"
"    if p == \"V\" or p == \"U\" then\n"
"      if ctx.rexw then sz = \"Q\"; ctx.rexw = false\n"
"      elseif ctx.o16 then sz = \"W\"; ctx.o16 = false\n"
"      elseif p == \"U\" and ctx.x64 then sz = \"Q\"\n"
"      else sz = \"D\" end\n"
"      regs = map_regs[sz]\n"
"    elseif p == \"T\" then\n"
"      if ctx.rexw then sz = \"Q\"; ctx.rexw = false else sz = \"D\" end\n"
"      regs = map_regs[sz]\n"
"    elseif p == \"B\" then\n"
"      sz = \"B\"\n"
"      regs = ctx.rex and map_regs.B64 or map_regs.B\n"
"    elseif match(p, \"[WDQMXYFG]\") then\n"
"      sz = p\n"
"      if sz == \"X\" and vexl then sz = \"Y\"; ctx.vexl = false end\n"
"      regs = map_regs[sz]\n"
"    elseif p == \"P\" then\n"
"      sz = ctx.o16 and \"X\" or \"M\"; ctx.o16 = false\n"
"      if sz == \"X\" and vexl then sz = \"Y\"; ctx.vexl = false end\n"
"      regs = map_regs[sz]\n"
"    elseif p == \"S\" then\n"
"      name = name..lower(sz)\n"
"    elseif p == \"s\" then\n"
"      local imm = getimm(ctx, pos, 1); if not imm then return end\n"
"      x = imm <= 127 and format(\"+0x%02x\", imm)\n"
"\t\t     or format(\"-0x%02x\", 256-imm)\n"
"      pos = pos+1\n"
"    elseif p == \"u\" then\n"
"      local imm = getimm(ctx, pos, 1); if not imm then return end\n"
"      x = format(\"0x%02x\", imm)\n"
"      pos = pos+1\n"
"    elseif p == \"b\" then\n"
"      local imm = getimm(ctx, pos, 1); if not imm then return end\n"
"      x = regs[imm/16+1]\n"
"      pos = pos+1\n"
"    elseif p == \"w\" then\n"
"      local imm = getimm(ctx, pos, 2); if not imm then return end\n"
"      x = format(\"0x%x\", imm)\n"
"      pos = pos+2\n"
"    elseif p == \"o\" then -- [offset]\n"
"      if ctx.x64 then\n"
"\tlocal imm1 = getimm(ctx, pos, 4); if not imm1 then return end\n"
"\tlocal imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end\n"
"\tx = format(\"[0x%08x%08x]\", imm2, imm1)\n"
"\tpos = pos+8\n"
"      else\n"
"\tlocal imm = getimm(ctx, pos, 4); if not imm then return end\n"
"\tx = format(\"[0x%08x]\", imm)\n"
"\tpos = pos+4\n"
"      end\n"
"    elseif p == \"i\" or p == \"I\" then\n"
"      local n = map_sz2n[sz]\n"
"      if n == 8 and ctx.x64 and p == \"I\" then\n"
"\tlocal imm1 = getimm(ctx, pos, 4); if not imm1 then return end\n"
"\tlocal imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end\n"
"\tx = format(\"0x%08x%08x\", imm2, imm1)\n"
"      else\n"
"\tif n == 8 then n = 4 end\n"
"\tlocal imm = getimm(ctx, pos, n); if not imm then return end\n"
"\tif sz == \"Q\" and (imm < 0 or imm > 0x7fffffff) then\n"
"\t  imm = (0xffffffff+1)-imm\n"
"\t  x = format(imm > 65535 and \"-0x%08x\" or \"-0x%x\", imm)\n"
"\telse\n"
"\t  x = format(imm > 65535 and \"0x%08x\" or \"0x%x\", imm)\n"
"\tend\n"
"      end\n"
"      pos = pos+n\n"
"    elseif p == \"j\" then\n"
"      local n = map_sz2n[sz]\n"
"      if n == 8 then n = 4 end\n"
"      local imm = getimm(ctx, pos, n); if not imm then return end\n"
"      if sz == \"B\" and imm > 127 then imm = imm-256\n"
"      elseif imm > 2147483647 then imm = imm-4294967296 end\n"
"      pos = pos+n\n"
"      imm = imm + pos + ctx.addr\n"
"      if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end\n"
"      ctx.imm = imm\n"
"      if sz == \"W\" then\n"
"\tx = format(\"word 0x%04x\", imm%65536)\n"
"      elseif ctx.x64 then\n"
"\tlocal lo = imm % 0x1000000\n"
"\tx = format(\"0x%02x%06x\", (imm-lo) / 0x1000000, lo)\n"
"      else\n"
"\tx = \"0x\"..tohex(imm)\n"
"      end\n"
"    elseif p == \"R\" then\n"
"      local r = byte(code, pos-1, pos-1)%8\n"
"      if ctx.rexb then r = r + 8; ctx.rexb = false end\n"
"      x = regs[r+1]\n"
"    elseif p == \"a\" then x = regs[1]\n"
"    elseif p == \"c\" then x = \"cl\"\n"
"    elseif p == \"d\" then x = \"dx\"\n"
"    elseif p == \"1\" then x = \"1\"\n"
"    else\n"
"      if not mode then\n"
"\tmode = ctx.mrm\n"
"\tif not mode then\n"
"\t  if pos > stop then return incomplete(ctx) end\n"
"\t  mode = byte(code, pos, pos)\n"
"\t  pos = pos+1\n"
"\tend\n"
"\trm = mode%8; mode = (mode-rm)/8\n"
"\tsp = mode%8; mode = (mode-sp)/8\n"
"\tsdisp = \"\"\n"
"\tif mode < 3 then\n"
"\t  if rm == 4 then\n"
"\t    if pos > stop then return incomplete(ctx) end\n"
"\t    sc = byte(code, pos, pos)\n"
"\t    pos = pos+1\n"
"\t    rm = sc%8; sc = (sc-rm)/8\n"
"\t    rx = sc%8; sc = (sc-rx)/8\n"
"\t    if ctx.rexx then rx = rx + 8; ctx.rexx = false end\n"
"\t    if rx == 4 then rx = nil end\n"
"\t  end\n"
"\t  if mode > 0 or rm == 5 then\n"
"\t    local dsz = mode\n"
"\t    if dsz ~= 1 then dsz = 4 end\n"
"\t    local disp = getimm(ctx, pos, dsz); if not disp then return end\n"
"\t    if mode == 0 then rm = nil end\n"
"\t    if rm or rx or (not sc and ctx.x64 and not ctx.a32) then\n"
"\t      if dsz == 1 and disp > 127 then\n"
"\t\tsdisp = format(\"-0x%x\", 256-disp)\n"
"\t      elseif disp >= 0 and disp <= 0x7fffffff then\n"
"\t\tsdisp = format(\"+0x%x\", disp)\n"
"\t      else\n"
"\t\tsdisp = format(\"-0x%x\", (0xffffffff+1)-disp)\n"
"\t      end\n"
"\t    else\n"
"\t      sdisp = format(ctx.x64 and not ctx.a32 and\n"
"\t\tnot (disp >= 0 and disp <= 0x7fffffff)\n"
"\t\tand \"0xffffffff%08x\" or \"0x%08x\", disp)\n"
"\t    end\n"
"\t    pos = pos+dsz\n"
"\t  end\n"
"\tend\n"
"\tif rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end\n"
"\tif ctx.rexr then sp = sp + 8; ctx.rexr = false end\n"
"      end\n"
"      if p == \"m\" then\n"
"\tif mode == 3 then x = regs[rm+1]\n"
"\telse\n"
"\t  local aregs = ctx.a32 and map_regs.D or ctx.aregs\n"
"\t  local srm, srx = \"\", \"\"\n"
"\t  if rm then srm = aregs[rm+1]\n"
"\t  elseif not sc and ctx.x64 and not ctx.a32 then srm = \"rip\" end\n"
"\t  ctx.a32 = false\n"
"\t  if rx then\n"
"\t    if rm then srm = srm..\"+\" end\n"
"\t    srx = aregs[rx+1]\n"
"\t    if sc > 0 then srx = srx..\"*\"..(2^sc) end\n"
"\t  end\n"
"\t  x = format(\"[%s%s%s]\", srm, srx, sdisp)\n"
"\tend\n"
"\tif mode < 3 and\n"
"\t   (not match(pat, \"[aRrgp]\") or match(pat, \"t\")) then -- Yuck.\n"
"\t  x = map_sz2prefix[sz]..\" \"..x\n"
"\tend\n"
"      elseif p == \"r\" then x = regs[sp+1]\n"
"      elseif p == \"g\" then x = map_segregs[sp+1]\n"
"      elseif p == \"p\" then -- Suppress prefix.\n"
"      elseif p == \"f\" then x = \"st\"..rm\n"
"      elseif p == \"x\" then\n"
"\tif sp == 0 and ctx.lock and not ctx.x64 then\n"
"\t  x = \"CR8\"; ctx.lock = false\n"
"\telse\n"
"\t  x = \"CR\"..sp\n"
"\tend\n"
"      elseif p == \"v\" then\n"
"\tif ctx.vexv then\n"
"\t  x = regs[ctx.vexv+1]; ctx.vexv = false\n"
"\tend\n"
"      elseif p == \"y\" then x = \"DR\"..sp\n"
"      elseif p == \"z\" then x = \"TR\"..sp\n"
"      elseif p == \"l\" then vexl = false\n"
"      elseif p == \"t\" then\n"
"      else\n"
"\terror(\"bad pattern `\"..pat..\"'\")\n"
"      end\n"
"    end\n"
"    if x then operands = operands and operands..\", \"..x or x end\n"
"  end\n"
"  ctx.pos = pos\n"
"  return putop(ctx, name, operands)\n"
"end\n"
"\n"
"-- Forward declaration.\n"
"local map_act\n"
"\n"
"-- Fetch and cache MRM byte.\n"
"local function getmrm(ctx)\n"
"  local mrm = ctx.mrm\n"
"  if not mrm then\n"
"    local pos = ctx.pos\n"
"    if pos > ctx.stop then return nil end\n"
"    mrm = byte(ctx.code, pos, pos)\n"
"    ctx.pos = pos+1\n"
"    ctx.mrm = mrm\n"
"  end\n"
"  return mrm\n"
"end\n"
"\n"
"-- Dispatch to handler depending on pattern.\n"
"local function dispatch(ctx, opat, patgrp)\n"
"  if not opat then return unknown(ctx) end\n"
"  if match(opat, \"%|\") then -- MMX/SSE variants depending on prefix.\n"
"    local p\n"
"    if ctx.rep then\n"
"      p = ctx.rep==\"rep\" and \"%|([^%|]*)\" or \"%|[^%|]*%|[^%|]*%|([^%|]*)\"\n"
"      ctx.rep = false\n"
"    elseif ctx.o16 then p = \"%|[^%|]*%|([^%|]*)\"; ctx.o16 = false\n"
"    else p = \"^[^%|]*\" end\n"
"    opat = match(opat, p)\n"
"    if not opat then return unknown(ctx) end\n"
"--    ctx.rep = false; ctx.o16 = false\n"
"    --XXX fails for 66 f2 0f 38 f1 06  crc32 eax,WORD PTR [esi]\n"
"    --XXX remove in branches\?\n"
"  end\n"
"  if match(opat, \"%$\") then -- reg$mem variants.\n"
"    local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end\n"
"    opat = match(opat, mrm >= 192 and \"^[^%$]*\" or \"%$(.*)\")\n"
"    if opat == \"\" then return unknown(ctx) end\n"
"  end\n"
"  if opat == \"\" then return unknown(ctx) end\n"
"  local name, pat = match(opat, \"^([a-z0-9 ]*)(.*)\")\n"
"  if pat == \"\" and patgrp then pat = patgrp end\n"
"  return map_act[sub(pat, 1, 1)](ctx, name, pat)\n"
"end\n"
"\n"
"-- Get a pattern from an opcode map and dispatch to handler.\n"
"local function dispatchmap(ctx, opcmap)\n"
"  local pos = ctx.pos\n"
"  local opat = opcmap[byte(ctx.code, pos, pos)]\n"
"  pos = pos + 1\n"
"  ctx.pos = pos\n"
"  return dispatch(ctx, opat)\n"
"end\n"
"\n"
"-- Map for action codes. The key is the first char after the name.\n"
"map_act = {\n"
"  -- Simple opcodes without operands.\n"
"  [\"\"] = function(ctx, name, pat)\n"
"    return putop(ctx, name)\n"
"  end,\n"
"\n"
"  -- Operand size chars fall right through.\n"
"  B = putpat, W = putpat, D = putpat, Q = putpat,\n"
"  V = putpat, U = putpat, T = putpat,\n"
"  M = putpat, X = putpat, P = putpat,\n"
"  F = putpat, G = putpat, Y = putpat,\n"
"\n"
"  -- Collect prefixes.\n"
"  [\":\"] = function(ctx, name, pat)\n"
"    ctx[pat == \":\" and name or sub(pat, 2)] = name\n"
"    if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.\n"
"  end,\n"
"\n"
"  -- Chain to special handler specified by name.\n"
"  [\"*\"] = function(ctx, name, pat)\n"
"    return map_act[name](ctx, name, sub(pat, 2))\n"
"  end,\n"
"\n"
"  -- Use named subtable for opcode group.\n"
"  [\"!\"] = function(ctx, name, pat)\n"
"    local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end\n"
"    return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))\n"
"  end,\n"
"\n"
"  -- o16,o32[,o64] variants.\n"
"  sz = function(ctx, name, pat)\n"
"    if ctx.o16 then ctx.o16 = false\n"
"    else\n"
"      pat = match(pat, \",(.*)\")\n"
"      if ctx.rexw then\n"
"\tlocal p = match(pat, \",(.*)\")\n"
"\tif p then pat = p; ctx.rexw = false end\n"
"      end\n"
"    end\n"
"    pat = match(pat, \"^[^,]*\")\n"
"    return dispatch(ctx, pat)\n"
"  end,\n"
"\n"
"  -- Two-byte opcode dispatch.\n"
"  opc2 = function(ctx, name, pat)\n"
"    return dispatchmap(ctx, map_opc2)\n"
"  end,\n"
"\n"
"  -- Three-byte opcode dispatch.\n"
"  opc3 = function(ctx, name, pat)\n"
"    return dispatchmap(ctx, map_opc3[pat])\n"
"  end,\n"
"\n"
"  -- VMX/SVM dispatch.\n"
"  vm = function(ctx, name, pat)\n"
"    return dispatch(ctx, map_opcvm[ctx.mrm])\n"
"  end,\n"
"\n"
"  -- Floating point opcode dispatch.\n"
"  fp = function(ctx, name, pat)\n"
"    local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end\n"
"    local rm = mrm%8\n"
"    local idx = pat*8 + ((mrm-rm)/8)%8\n"
"    if mrm >= 192 then idx = idx + 64 end\n"
"    local opat = map_opcfp[idx]\n"
"    if type(opat) == \"table\" then opat = opat[rm+1] end\n"
"    return dispatch(ctx, opat)\n"
"  end,\n"
"\n"
"  -- REX prefix.\n"
"  rex = function(ctx, name, pat)\n"
"    if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.\n"
"    for p in gmatch(pat, \".\") do ctx[\"rex\"..p] = true end\n"
"    ctx.rex = \"rex\"\n"
"  end,\n"
"\n"
"  -- VEX prefix.\n"
"  vex = function(ctx, name, pat)\n"
"    if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.\n"
"    ctx.rex = \"vex\"\n"
"    local pos = ctx.pos\n"
"    if ctx.mrm then\n"
"      ctx.mrm = nil\n"
"      pos = pos-1\n"
"    end\n"
"    local b = byte(ctx.code, pos, pos)\n"
"    if not b then return incomplete(ctx) end\n"
"    pos = pos+1\n"
"    if b < 128 then ctx.rexr = true end\n"
"    local m = 1\n"
"    if pat == \"3\" then\n"
"      m = b%32; b = (b-m)/32\n"
"      local nb = b%2; b = (b-nb)/2\n"
"      if nb == 0 then ctx.rexb = true end\n"
"      local nx = b%2\n"
"      if nx == 0 then ctx.rexx = true end\n"
"      b = byte(ctx.code, pos, pos)\n"
"      if not b then return incomplete(ctx) end\n"
"      pos = pos+1\n"
"      if b >= 128 then ctx.rexw = true end\n"
"    end\n"
"    ctx.pos = pos\n"
"    local map\n"
"    if m == 1 then map = map_opc2\n"
"    elseif m == 2 then map = map_opc3[\"38\"]\n"
"    elseif m == 3 then map = map_opc3[\"3a\"]\n"
"    else return unknown(ctx) end\n"
"    local p = b%4; b = (b-p)/4\n"
"    if p == 1 then ctx.o16 = \"o16\"\n"
"    elseif p == 2 then ctx.rep = \"rep\"\n"
"    elseif p == 3 then ctx.rep = \"repne\" end\n"
"    local l = b%2; b = (b-l)/2\n"
"    if l ~= 0 then ctx.vexl = true end\n"
"    ctx.vexv = (-1-b)%16\n"
"    return dispatchmap(ctx, map)\n"
"  end,\n"
"\n"
"  -- Special case for nop with REX prefix.\n"
"  nop = function(ctx, name, pat)\n"
"    return dispatch(ctx, ctx.rex and pat or \"nop\")\n"
"  end,\n"
"\n"
"  -- Special case for 0F 77.\n"
"  emms = function(ctx, name, pat)\n"
"    if ctx.rex ~= \"vex\" then\n"
"      return putop(ctx, \"emms\")\n"
"    elseif ctx.vexl then\n"
"      ctx.vexl = false\n"
"      return putop(ctx, \"zeroall\")\n"
"    else\n"
"      return putop(ctx, \"zeroupper\")\n"
"    end\n"
"  end,\n"
"}\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Disassemble a block of code.\n"
"local function disass_block(ctx, ofs, len)\n"
"  if not ofs then ofs = 0 end\n"
"  local stop = len and ofs+len or #ctx.code\n"
"  ofs = ofs + 1\n"
"  ctx.start = ofs\n"
"  ctx.pos = ofs\n"
"  ctx.stop = stop\n"
"  ctx.imm = nil\n"
"  ctx.mrm = false\n"
"  clearprefixes(ctx)\n"
"  while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end\n"
"  if ctx.pos ~= ctx.start then incomplete(ctx) end\n"
"end\n"
"\n"
"-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).\n"
"local function create(code, addr, out)\n"
"  local ctx = {}\n"
"  ctx.code = code\n"
"  ctx.addr = (addr or 0) - 1\n"
"  ctx.out = out or io.write\n"
"  ctx.symtab = {}\n"
"  ctx.disass = disass_block\n"
"  ctx.hexdump = 16\n"
"  ctx.x64 = false\n"
"  ctx.map1 = map_opc1_32\n"
"  ctx.aregs = map_regs.D\n"
"  return ctx\n"
"end\n"
"\n"
"local function create64(code, addr, out)\n"
"  local ctx = create(code, addr, out)\n"
"  ctx.x64 = true\n"
"  ctx.map1 = map_opc1_64\n"
"  ctx.aregs = map_regs.Q\n"
"  return ctx\n"
"end\n"
"\n"
"-- Simple API: disassemble code (a string) at address and output via out.\n"
"local function disass(code, addr, out)\n"
"  create(code, addr, out):disass()\n"
"end\n"
"\n"
"local function disass64(code, addr, out)\n"
"  create64(code, addr, out):disass()\n"
"end\n"
"\n"
"-- Return register name for RID.\n"
"local function regname(r)\n"
"  if r < 8 then return map_regs.D[r+1] end\n"
"  return map_regs.X[r-7]\n"
"end\n"
"\n"
"local function regname64(r)\n"
"  if r < 16 then return map_regs.Q[r+1] end\n"
"  return map_regs.X[r-15]\n"
"end\n"
"\n"
"-- Public module functions.\n"
"return {\n"
"  create = create,\n"
"  create64 = create64,\n"
"  disass = disass,\n"
"  disass64 = disass64,\n"
"  regname = regname,\n"
"  regname64 = regname64\n"
"}\n"
"\n"
""
;
