aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/LuaJIT-1.1.7/jit/dis_x86.lua
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/LuaJIT-1.1.7/jit/dis_x86.lua')
-rw-r--r--libraries/LuaJIT-1.1.7/jit/dis_x86.lua622
1 files changed, 622 insertions, 0 deletions
diff --git a/libraries/LuaJIT-1.1.7/jit/dis_x86.lua b/libraries/LuaJIT-1.1.7/jit/dis_x86.lua
new file mode 100644
index 0000000..b9ca150
--- /dev/null
+++ b/libraries/LuaJIT-1.1.7/jit/dis_x86.lua
@@ -0,0 +1,622 @@
1----------------------------------------------------------------------------
2-- LuaJIT x86 disassembler module.
3--
4-- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
5-- Released under the MIT/X license. See luajit.h for full copyright notice.
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 P4 or K8 implements in 32 bit
17-- mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3 and even privileged
18-- instructions.
19--
20-- Notes:
21-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
22-- * No attempt at optimization has been made -- it's fast enough for my needs.
23-- * The public API may change when more architectures are added.
24--
25-- TODO:
26-- * More testing with arbitrary x86 code (not just LuaJIT generated code).
27-- * The output for a few MMX/SSE opcodes could be improved.
28-- * Adding x64 support would be straightforward.
29-- * Better input API (iterator) and output API (structured access to instr).
30------------------------------------------------------------------------------
31
32local type = type
33local sub, byte, format = string.sub, string.byte, string.format
34local match, gmatch, gsub = string.match, string.gmatch, string.gsub
35
36-- Map for 1st opcode byte. Ugly? Well ... read on.
37local map_opc1 = {
38--0x
39[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
40"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
41--1x
42"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
43"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
44--2x
45"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
46"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
47--3x
48"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
49"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
50--4x
51"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
52"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
53--5x
54"pushVR","pushVR","pushVR","pushVR","pushVR","pushVR","pushVR","pushVR",
55"popVR","popVR","popVR","popVR","popVR","popVR","popVR","popVR",
56--6x
57"pusha/pushaw","popa/popaw","boundVrm","arplWmr",
58"fs:seg","gs:seg","o16:","a16",
59"pushVi","imulVrmi","pushBs","imulVrms",
60"insb","insd/insw","outsb","outsd/outsw",
61--7x
62"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
63"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
64--8x
65"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
66"testBmr","testVmr","xchgBrm","xchgVrm",
67"movBmr","movVmr","movBrm","movVrm",
68"movVmg","leaVrm","movWgm","popVm",
69--9x
70"nop|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
71"xchgVaR","xchgVaR","xchgVaR","xchgVaR",
72"cwde/cbw","cdq/cwd","call farViw","wait",
73"pushf/pushfw","popf/popfw","sahf","lahf",
74--Ax
75"movBao","movVao","movBoa","movVoa",
76"movsb","movsd/movsb","cmpsb","cmpsd/cmpsw",
77"testBai","testVai","stosb","stosd/stosw",
78"lodsb","lodsd/lodsw","scasb","scasd/scasw",
79--Bx
80"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
81"movVRi","movVRi","movVRi","movVRi","movVRi","movVRi","movVRi","movVRi",
82--Cx
83"shift!Bmu","shift!Vmu","retBw","ret","lesVrm","ldsVrm","movBmi","movVmi",
84"enterBwu","leave","retfBw","retf","int3","intBu","into","iret/iretw",
85--Dx
86"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
87"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
88--Ex
89"loopneBj","loopeBj","loopBj","jecxz/jcxzBj","inBau","inVau","outBua","outVua",
90"callDj","jmpDj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
91--Fx
92"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
93"clc","stc","cli","sti","cld","std","inc!Bm","inc!Vm",
94}
95assert(#map_opc1 == 255)
96
97-- Map for 2nd opcode byte (0f xx). True CISC hell. Hey, I told you.
98-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne
99local map_opc2 = {
100--0x
101[0]="sldt!Dmp","sgdt!Dmp","larVrm","lslVrm",nil,"syscall","clts","sysret",
102"invd","wbinvd",nil,"ud1",nil,"prefetch!Bm","femms","3dnowMrmu",
103--1x
104"movupsXrm|movssXrm|movupdXrm|movsdXrm",
105"movupsXmr|movssXmr|movupdXmr|movsdXmr",
106"movhlpsXrm|movsldupXrm|movlpdXrm|movddupXrm", -- TODO: movlpsXrMm (mem case).
107"movlpsXmr||movlpdXmr",
108"unpcklpsXrm||unpcklpdXrm",
109"unpckhpsXrm||unpckhpdXrm",
110"movlhpsXrm|movshdupXrm|movhpdXrm", -- TODO: movhpsXrMm (mem case).
111"movhpsXmr||movhpdXmr",
112"prefetcht!Bm","hintnopBm","hintnopBm","hintnopBm",
113"hintnopBm","hintnopBm","hintnopBm","hintnopBm",
114--2x
115"movDmx","movDmy","movDxm","movDym","movDmz",nil,"movDzm",nil,
116"movapsXrm||movapdXrm",
117"movapsXmr||movapdXmr",
118"cvtpi2psXrMm|cvtsi2ssXrDm|cvtpi2pdXrMm|cvtsi2sdXrDm",
119"movntpsXmr||movntpdXmr",
120"cvttps2piMrXm|cvttss2siDrXm|cvttpd2piMrXm|cvttsd2siDrXm",
121"cvtps2piMrXm|cvtss2siDrXm|cvtpd2piMrXm|cvtsd2siDrXm",
122"ucomissXrm||ucomisdXrm",
123"comissXrm||comisdXrm",
124--3x
125"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,nil,
126"ssse3*38",nil,"ssse3*3a",nil,nil,nil,nil,nil,
127--4x
128"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
129"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
130"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
131"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
132--5x
133"movmskpsDrXm||movmskpdDrXm","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
134"rsqrtpsXrm|rsqrtssXrm","rcppsXrm|rcpssXrm",
135"andpsXrm||andpdXrm","andnpsXrm||andnpdXrm",
136"orpsXrm||orpdXrm","xorpsXrm||xorpdXrm",
137"addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm",
138"cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm",
139"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
140"subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm",
141"divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm",
142--6x
143"punpcklbwMrm||punpcklbqXrm","punpcklwdPrm","punpckldqPrm","packsswbPrm",
144"pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm",
145"punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm",
146"||punpcklqdqXrm","||punpckhqdqXrm",
147"movdPrDm","movqMrm|movdquXrm|movdqaXrm",
148--7x
149"pshufwPrmu","pshiftw!Pmu","pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu",
150"pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|",
151nil,nil,nil,nil,
152"||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm",
153"movdDmMr|movqXrm|movdDmXr","movqMmr|movdquXmr|movdqaXmr",
154--8x
155"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
156"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
157--9x
158"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
159"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
160--Ax
161"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
162"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
163--Bx
164"cmpxchgBmr","cmpxchgVmr","lssVrm","btrVmr",
165"lfsVrm","lgsVrm","movzxVrBm","movzxDrWm",
166nil,"ud2","bt!Vmu","btcVmr",
167"bsfVrm","bsrVrm","movsxVrBm","movsxDrWm",
168--Cx
169"xaddBmr","xaddVmr",
170"cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","movntiDmr|",
171"pinsrwPrWmu","pextrwDrPmu",
172"shufpsXrmu||shufpdXrmu","cmpxchg!Dmp",
173"bswapDR","bswapDR","bswapDR","bswapDR","bswapDR","bswapDR","bswapDR","bswapDR",
174--Dx
175"||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm",
176"paddqPrm","pmullwPrm",
177"|movq2dqXrMm|movqXmr|movdq2qMrXm","pmovmskbDrPm",
178"psubusbPrm","psubuswPrm","pminubPrm","pandPrm",
179"paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm",
180--Ex
181"pavgbPrm","psrawPrm","psradPrm","pavgwPrm",
182"pmulhuwPrm","pmulhwPrm",
183"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","movntqMmr||movntdqXmr",
184"psubsbPrm","psubswPrm","pminswPrm","porPrm",
185"paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm",
186--Fx
187"|||lddquXrm","psllwPrm","pslldPrm","psllqPrm",
188"pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm",
189"psubbPrm","psubwPrm","psubdPrm","psubqPrm",
190"paddbPrm","paddwPrm","padddPrm","ud",
191}
192assert(map_opc2[255] == "ud")
193
194-- Map for SSSE3 opcodes.
195local map_ssse3 = {
196["38"] = { -- [66] 0f 38 xx
197--0x
198[0]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm",
199"pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm",
200"psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm",
201nil,nil,nil,nil,
202--1x
203nil,nil,nil,nil,nil,nil,nil,nil,
204nil,nil,nil,nil,"pabsbPrm","pabswPrm","pabsdPrm",nil,
205},
206["3a"] = { -- [66] 0f 3a xx
207[0x0f] = "palignrPrmu",
208},
209}
210
211-- Map for FP opcodes. And you thought stack machines are simple?
212local map_opcfp = {
213-- D8-DF 00-BF: opcodes with a memory operand.
214-- D8
215[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
216"fldFm",nil,"fstFm","fstpFm","fldenvDmp","fldcwWm","fnstenvDmp","fnstcwWm",
217-- DA
218"fiaddDm","fimulDm","ficomDm","ficompDm",
219"fisubDm","fisubrDm","fidivDm","fidivrDm",
220-- DB
221"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
222-- DC
223"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
224-- DD
225"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
226-- DE
227"fiaddWm","fimulWm","ficomWm","ficompWm",
228"fisubWm","fisubrWm","fidivWm","fidivrWm",
229-- DF
230"fildWm","fisttpWm","fistWm","fistpWm",
231"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
232-- xx C0-FF: opcodes with a pseudo-register operand.
233-- D8
234"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
235-- D9
236"fldFf","fxchFf",{"fnop"},nil,
237{"fchs","fabs",nil,nil,"ftst","fxam"},
238{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
239{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
240{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
241-- DA
242"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
243-- DB
244"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
245{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
246-- DC
247"fadd toFf","fmul toFf",nil,nil,
248"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
249-- DD
250"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
251-- DE
252"faddpFf","fmulpFf",nil,{nil,"fcompp"},
253"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
254-- DF
255nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
256}
257assert(map_opcfp[126] == "fcomipFf")
258
259-- Map for opcode groups. The subkey is sp from the ModRM byte.
260local map_opcgroup = {
261 arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
262 shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
263 testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
264 testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
265 inc = { "inc", "dec", "callDmp", "call farDmp",
266 "jmpDmp", "jmp farDmp", "push" },
267 sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
268 sgdt = { "sgdt", "sidt", "lgdt", "lidt", "smsw", nil, "lmsw", "invlpg" },
269 bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
270 cmpxchg = { nil, "cmpxchg8b" },
271 pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
272 pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
273 pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
274 pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
275 fxsave = { "fxsave", "fxrstor", "ldmxcsr", "stmxcsr",
276 nil, "lfenceDp", "mfenceDp", "sfenceDp" }, -- TODO: clflush.
277 prefetch = { "prefetch", "prefetchw" },
278 prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
279}
280
281------------------------------------------------------------------------------
282
283-- Maps for register names.
284local map_aregs = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }
285local map_regs = {
286 B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" },
287 W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" },
288 D = map_aregs,
289 M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" },
290 X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" },
291}
292local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
293
294-- Maps for size names.
295local map_sz2n = {
296 B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16,
297}
298local map_sz2prefix = {
299 B = "byte", W = "word", D = "dword",
300 Q = "qword", -- No associated reg in 32 bit mode.
301 F = "dword", G = "qword", -- No need for sizes/register names for these two.
302 M = "qword", X = "xword",
303}
304
305------------------------------------------------------------------------------
306
307-- Output a nicely formatted line with an opcode and operands.
308local function putop(ctx, text, operands)
309 local code, pos, hex = ctx.code, ctx.pos, ""
310 for i=ctx.start,pos-1 do
311 hex = hex..format("%02X", byte(code, i, i))
312 end
313 if #hex > 16 then hex = sub(hex, 1, 16).."." end
314 if operands then text = text.." "..operands end
315 if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
316 if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
317 if ctx.seg then
318 local text2, n = gsub(text, "%[", "["..ctx.seg..":")
319 if n == 0 then text = ctx.seg.." "..text else text = text2 end
320 ctx.seg = false
321 end
322 if ctx.lock then text = "lock "..text; ctx.lock = false end
323 local imm = ctx.imm
324 if imm then
325 local sym = ctx.symtab[imm]
326 if sym then text = text.."\t->"..sym end
327 end
328 ctx.out(format("%08x %-18s%s\n", ctx.addr+ctx.start, hex, text))
329 ctx.mrm = false
330 ctx.start = pos
331 ctx.imm = nil
332end
333
334-- Fallback for incomplete opcodes at the end.
335local function incomplete(ctx)
336 ctx.pos = ctx.stop+1
337 ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
338 return putop(ctx, "(incomplete)")
339end
340
341-- Fallback for unknown opcodes.
342local function unknown(ctx)
343 ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
344 return putop(ctx, "(unknown)")
345end
346
347-- Return an immediate of the specified size.
348local function getimm(ctx, pos, n)
349 if pos+n-1 > ctx.stop then return incomplete(ctx) end
350 local code = ctx.code
351 if n == 1 then
352 local b1 = byte(code, pos, pos)
353 return b1
354 elseif n == 2 then
355 local b1, b2 = byte(code, pos, pos+1)
356 return b1+b2*256
357 else
358 local b1, b2, b3, b4 = byte(code, pos, pos+3)
359 local imm = b1+b2*256+b3*65536+b4*16777216
360 ctx.imm = imm
361 return imm
362 end
363end
364
365-- Process pattern string and generate the operands.
366local function putpat(ctx, name, pat)
367 local operands, regs, sz, mode, sp, rm, sc, rx, disp, sdisp
368 local code, pos, stop = ctx.code, ctx.pos, ctx.stop
369
370 -- Chars used: 1DFGMPQRVWXacdfgijmoprsuwxyz
371 for p in gmatch(pat, ".") do
372 local x = nil
373 if p == "V" then
374 sz = ctx.o16 and "W" or "D"; ctx.o16 = false
375 regs = map_regs[sz]
376 elseif match(p, "[BWDQFGMX]") then
377 sz = p
378 regs = map_regs[sz]
379 elseif p == "P" then
380 sz = ctx.o16 and "X" or "M"; ctx.o16 = false
381 regs = map_regs[sz]
382 elseif p == "s" then
383 local imm = getimm(ctx, pos, 1); if not imm then return end
384 x = imm <= 127 and format("byte +0x%02x", imm)
385 or format("byte -0x%02x", 256-imm)
386 pos = pos+1
387 elseif p == "u" then
388 local imm = getimm(ctx, pos, 1); if not imm then return end
389 x = format("0x%02x", imm)
390 pos = pos+1
391 elseif p == "w" then
392 local imm = getimm(ctx, pos, 2); if not imm then return end
393 x = format("0x%x", imm)
394 pos = pos+2
395 elseif p == "o" then -- [offset]
396 local imm = getimm(ctx, pos, 4); if not imm then return end
397 x = format("[0x%08x]", imm)
398 pos = pos+4
399 elseif p == "i" then
400 local n = map_sz2n[sz]
401 local imm = getimm(ctx, pos, n); if not imm then return end
402 x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
403 pos = pos+n
404 elseif p == "j" then
405 local n = map_sz2n[sz]
406 local imm = getimm(ctx, pos, n); if not imm then return end
407 if sz == "B" and imm > 127 then imm = imm-256
408 elseif imm > 2147483647 then imm = imm-4294967296 end
409 pos = pos+n
410 imm = imm + pos + ctx.addr
411 ctx.imm = imm
412 x = sz == "W" and format("word 0x%04x", imm%65536)
413 or format("0x%08x", imm)
414 elseif p == "R" then x = regs[byte(code, pos-1, pos-1)%8+1]
415 elseif p == "a" then x = regs[1]
416 elseif p == "c" then x = "cl"
417 elseif p == "d" then x = "dx"
418 elseif p == "1" then x = "1"
419 else
420 if not mode then
421 mode = ctx.mrm
422 if not mode then
423 if pos > stop then return incomplete(ctx) end
424 mode = byte(code, pos, pos)
425 pos = pos+1
426 end
427 rm = mode%8; mode = (mode-rm)/8
428 sp = mode%8; mode = (mode-sp)/8
429 sdisp = ""
430 if mode < 3 then
431 if rm == 4 then
432 if pos > stop then return incomplete(ctx) end
433 sc = byte(code, pos, pos)
434 pos = pos+1
435 rm = sc%8; sc = (sc-rm)/8
436 rx = sc%8; sc = (sc-rx)/8
437 if rx == 4 then rx = nil end
438 end
439 if mode > 0 or rm == 5 then
440 local dsz = mode
441 if dsz ~= 1 then dsz = 4 end
442 disp = getimm(ctx, pos, dsz); if not disp then return end
443 sdisp = (dsz == 4 or disp <= 127) and
444 format(disp > 65535 and "+0x%08x" or "+0x%x", disp) or
445 format("-0x%x", 256-disp)
446 pos = pos+dsz
447 end
448 end
449 end
450 if p == "m" then
451 if mode == 3 then x = regs[rm+1]
452 else
453 local srm, srx = map_aregs[rm+1], ""
454 if rx then
455 srm = srm.."+"
456 srx = map_aregs[rx+1]
457 if sc > 0 then srx = srx.."*"..(2^sc) end
458 end
459 if mode == 0 and rm == 5 then
460 srm = ""
461 sdisp = format("%s0x%08x", rx and "+" or "", disp)
462 end
463 x = format("[%s%s%s]", srm, srx, sdisp)
464 end
465 if mode < 3 and
466 (not match(pat, "[aRrgp]") or
467 name == "movzx" or name == "movsx") then -- Yuck.
468 x = map_sz2prefix[sz].." "..x
469 end
470 elseif p == "r" then x = regs[sp+1]
471 elseif p == "g" then x = map_segregs[sp+1]
472 elseif p == "p" then -- Suppress prefix.
473 elseif p == "f" then x = "st"..rm
474 elseif p == "x" then x = "CR"..sp
475 elseif p == "y" then x = "DR"..sp
476 elseif p == "z" then x = "TR"..sp
477 else
478 error("bad pattern `"..pat.."'")
479 end
480 end
481 if x then operands = operands and operands..","..x or x end
482 end
483 ctx.pos = pos
484 return putop(ctx, name, operands)
485end
486
487-- Forward declaration.
488local map_act
489
490-- Get a pattern from an opcode map and dispatch to handler.
491local function opcdispatch(ctx, opcmap)
492 local pos = ctx.pos
493 local opat = opcmap[byte(ctx.code, pos, pos)]
494 if not opat then return unknown(ctx) end
495 if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
496 local p
497 if ctx.rep then p = ctx.rep=="rep" and "%|([^%|]*)" or "%|.-%|.-%|([^%|]*)"
498 elseif ctx.o16 then p = "%|.-%|([^%|]*)"
499 else p = "^[^%|]*" end
500 opat = match(opat, p)
501 if not opat or opat == "" then return unknown(ctx) end
502 ctx.rep = false; ctx.o16 = false
503 end
504 local name, pat, act = match(opat, "^([a-z0-9 ]*)((.?).*)")
505 ctx.pos = pos + 1
506 return map_act[act](ctx, name, pat)
507end
508
509-- Map for action codes. The key is the first char after the name.
510map_act = {
511 -- Simple opcodes without operands.
512 [""] = function(ctx, name, pat)
513 return putop(ctx, name)
514 end,
515
516 -- Operand size chars fall right through.
517 B = putpat, W = putpat, D = putpat, V = putpat,
518 F = putpat, G = putpat,
519 M = putpat, X = putpat, P = putpat,
520
521 -- Collect prefixes.
522 [":"] = function(ctx, name, pat)
523 ctx[pat == ":" and name or sub(pat, 2)] = name
524 end,
525
526 -- Select alternate opcode name when prefixed with o16.
527 ["/"] = function(ctx, name, pat)
528 local wname, rpat = match(pat, "^/([a-z0-9 ]+)(.*)")
529 if ctx.o16 then name = wname; ctx.o16 = false end
530 return putpat(ctx, name, rpat)
531 end,
532
533 -- Chain to special handler specified by name.
534 ["*"] = function(ctx, name, pat)
535 return map_act[name](ctx, name, sub(pat, 2))
536 end,
537
538 -- Use named subtable for opcode group.
539 ["!"] = function(ctx, name, pat)
540
541 local pos = ctx.pos
542 if pos > ctx.stop then return incomplete(ctx) end
543 local mrm = byte(ctx.code, pos, pos)
544 ctx.pos = pos+1
545 ctx.mrm = mrm
546
547 local opat = map_opcgroup[name][((mrm-(mrm%8))/8)%8+1]
548 if not opat then return unknown(ctx) end
549 local name, pat2 = match(opat, "^([a-z0-9 ]*)(.*)")
550 return putpat(ctx, name, pat2 ~= "" and pat2 or sub(pat, 2))
551 end,
552
553 -- Two-byte opcode dispatch.
554 opc2 = function(ctx, name, pat)
555 return opcdispatch(ctx, map_opc2)
556 end,
557
558 -- SSSE3 dispatch.
559 ssse3 = function(ctx, name, pat)
560 return opcdispatch(ctx, map_ssse3[pat])
561 end,
562
563 -- Floating point opcode dispatch.
564 fp = function(ctx, name, pat)
565
566 local pos = ctx.pos
567 if pos > ctx.stop then return incomplete(ctx) end
568 local mrm = byte(ctx.code, pos, pos)
569 ctx.pos = pos+1
570 ctx.mrm = mrm
571
572 local rm = mrm%8
573 local idx = pat*8 + ((mrm-rm)/8)%8
574 if mrm >= 192 then idx = idx + 64 end
575 local opat = map_opcfp[idx]
576 if type(opat) == "table" then opat = opat[rm+1] end
577 if not opat then return unknown(ctx) end
578 local name, pat2 = match(opat, "^([a-z0-9 ]*)(.*)")
579 return putpat(ctx, name, pat2)
580 end,
581}
582
583------------------------------------------------------------------------------
584
585-- Disassemble a block of code.
586local function disass_block(ctx, ofs, len)
587 if not ofs then ofs = 0 end
588 local stop = len and ofs+len or #ctx.code
589 ofs = ofs + 1
590 ctx.start = ofs
591 ctx.pos = ofs
592 ctx.stop = stop
593 ctx.imm = nil
594 ctx.mrm = false
595 ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
596 while ctx.pos <= stop do opcdispatch(ctx, map_opc1) end
597 if ctx.pos ~= ctx.start then incomplete(ctx) end
598end
599
600-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
601local function create_(code, addr, out)
602 local ctx = {}
603 ctx.code = code
604 ctx.addr = (addr or 0) - 1
605 ctx.out = out or io.write
606 ctx.symtab = {}
607 ctx.disass = disass_block
608 return ctx
609end
610
611-- Simple API: disassemble code (a string) at address and output via out.
612local function disass_(code, addr, out)
613 create_(code, addr, out):disass()
614end
615
616
617-- Public module functions.
618module(...)
619
620create = create_
621disass = disass_
622