aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/LuaJIT-1.1.7/dynasm/dasm_x86.lua
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/LuaJIT-1.1.7/dynasm/dasm_x86.lua')
-rw-r--r--libraries/LuaJIT-1.1.7/dynasm/dasm_x86.lua1581
1 files changed, 0 insertions, 1581 deletions
diff --git a/libraries/LuaJIT-1.1.7/dynasm/dasm_x86.lua b/libraries/LuaJIT-1.1.7/dynasm/dasm_x86.lua
deleted file mode 100644
index 026c3b0..0000000
--- a/libraries/LuaJIT-1.1.7/dynasm/dasm_x86.lua
+++ /dev/null
@@ -1,1581 +0,0 @@
1------------------------------------------------------------------------------
2-- DynASM x86 module.
3--
4-- Copyright (C) 2005-2008 Mike Pall. All rights reserved.
5-- See dynasm.lua for full copyright notice.
6------------------------------------------------------------------------------
7
8-- Module information:
9local _info = {
10 arch = "x86",
11 description = "DynASM x86 (i386) module",
12 version = "1.1.4",
13 vernum = 10104,
14 release = "2008-01-29",
15 author = "Mike Pall",
16 license = "MIT",
17}
18
19-- Exported glue functions for the arch-specific module.
20local _M = { _info = _info }
21
22-- Cache library functions.
23local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
24local assert, unpack = assert, unpack
25local _s = string
26local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
27local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub
28local concat, sort = table.concat, table.sort
29local char, unpack = string.char, unpack
30
31-- Inherited tables and callbacks.
32local g_opt, g_arch
33local wline, werror, wfatal, wwarn
34
35-- Action name list.
36-- CHECK: Keep this in sync with the C code!
37local action_names = {
38 -- int arg, 1 buffer pos:
39 "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB",
40 -- action arg (1 byte), int arg, 1 buffer pos (num):
41 "SPACE",
42 -- ptrdiff_t arg, 1 buffer pos (address): !x64
43 "SETLABEL", "REL_A",
44 -- action arg (1 byte) or int arg, 2 buffer pos (link, offset):
45 "REL_LG", "REL_PC",
46 -- action arg (1 byte) or int arg, 1 buffer pos (link):
47 "IMM_LG", "IMM_PC",
48 -- action arg (1 byte) or int arg, 1 buffer pos (offset):
49 "LABEL_LG", "LABEL_PC",
50 -- action arg (1 byte), 1 buffer pos (offset):
51 "ALIGN",
52 -- action arg (1 byte), no buffer pos.
53 "ESC",
54 -- no action arg, no buffer pos.
55 "MARK",
56 -- action arg (1 byte), no buffer pos, terminal action:
57 "SECTION",
58 -- no args, no buffer pos, terminal action:
59 "STOP"
60}
61
62-- Maximum number of section buffer positions for dasm_put().
63-- CHECK: Keep this in sync with the C code!
64local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
65
66-- Action name -> action number (dynamically generated below).
67local map_action = {}
68-- First action number. Everything below does not need to be escaped.
69local actfirst = 256-#action_names
70
71-- Action list buffer and string (only used to remove dupes).
72local actlist = {}
73local actstr = ""
74
75-- Argument list for next dasm_put(). Start with offset 0 into action list.
76local actargs = { 0 }
77
78-- Current number of section buffer positions for dasm_put().
79local secpos = 1
80
81------------------------------------------------------------------------------
82
83-- Compute action numbers for action names.
84for n,name in ipairs(action_names) do
85 local num = actfirst + n - 1
86 map_action[name] = num
87end
88
89-- Dump action names and numbers.
90local function dumpactions(out)
91 out:write("DynASM encoding engine action codes:\n")
92 for n,name in ipairs(action_names) do
93 local num = map_action[name]
94 out:write(format(" %-10s %02X %d\n", name, num, num))
95 end
96 out:write("\n")
97end
98
99-- Write action list buffer as a huge static C array.
100local function writeactions(out, name)
101 local nn = #actlist
102 local last = actlist[nn] or 255
103 actlist[nn] = nil -- Remove last byte.
104 if nn == 0 then nn = 1 end
105 out:write("static const unsigned char ", name, "[", nn, "] = {\n")
106 local s = " "
107 for n,b in ipairs(actlist) do
108 s = s..b..","
109 if #s >= 75 then
110 assert(out:write(s, "\n"))
111 s = " "
112 end
113 end
114 out:write(s, last, "\n};\n\n") -- Add last byte back.
115end
116
117------------------------------------------------------------------------------
118
119-- Add byte to action list.
120local function wputxb(n)
121 assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range")
122 actlist[#actlist+1] = n
123end
124
125-- Add action to list with optional arg. Advance buffer pos, too.
126local function waction(action, a, num)
127 wputxb(assert(map_action[action], "bad action name `"..action.."'"))
128 if a then actargs[#actargs+1] = a end
129 if a or num then secpos = secpos + (num or 1) end
130end
131
132-- Add call to embedded DynASM C code.
133local function wcall(func, args)
134 wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)
135end
136
137-- Delete duplicate action list chunks. A tad slow, but so what.
138local function dedupechunk(offset)
139 local al, as = actlist, actstr
140 local chunk = char(unpack(al, offset+1, #al))
141 local orig = find(as, chunk, 1, true)
142 if orig then
143 actargs[1] = orig-1 -- Replace with original offset.
144 for i=offset+1,#al do al[i] = nil end -- Kill dupe.
145 else
146 actstr = as..chunk
147 end
148end
149
150-- Flush action list (intervening C code or buffer pos overflow).
151local function wflush(term)
152 local offset = actargs[1]
153 if #actlist == offset then return end -- Nothing to flush.
154 if not term then waction("STOP") end -- Terminate action list.
155 dedupechunk(offset)
156 wcall("put", actargs) -- Add call to dasm_put().
157 actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
158 secpos = 1 -- The actionlist offset occupies a buffer position, too.
159end
160
161-- Put escaped byte.
162local function wputb(n)
163 if n >= actfirst then waction("ESC") end -- Need to escape byte.
164 wputxb(n)
165end
166
167------------------------------------------------------------------------------
168
169-- Global label name -> global label number. With auto assignment on 1st use.
170local next_global = 10
171local map_global = setmetatable({}, { __index = function(t, name)
172 if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
173 local n = next_global
174 if n > 246 then werror("too many global labels") end
175 next_global = n + 1
176 t[name] = n
177 return n
178end})
179
180-- Dump global labels.
181local function dumpglobals(out, lvl)
182 local t = {}
183 for name, n in pairs(map_global) do t[n] = name end
184 out:write("Global labels:\n")
185 for i=10,next_global-1 do
186 out:write(format(" %s\n", t[i]))
187 end
188 out:write("\n")
189end
190
191-- Write global label enum.
192local function writeglobals(out, prefix)
193 local t = {}
194 for name, n in pairs(map_global) do t[n] = name end
195 out:write("enum {\n")
196 for i=10,next_global-1 do
197 out:write(" ", prefix, t[i], ",\n")
198 end
199 out:write(" ", prefix, "_MAX\n};\n")
200end
201
202------------------------------------------------------------------------------
203
204-- Arch-specific maps.
205local map_archdef = {} -- Ext. register name -> int. name.
206local map_reg_rev = {} -- Int. register name -> ext. name.
207local map_reg_num = {} -- Int. register name -> register number.
208local map_reg_opsize = {} -- Int. register name -> operand size.
209local map_reg_valid_base = {} -- Int. register name -> valid base register?
210local map_reg_valid_index = {} -- Int. register name -> valid index register?
211local reg_list = {} -- Canonical list of int. register names.
212
213local map_type = {} -- Type name -> { ctype, reg }
214local ctypenum = 0 -- Type number (for _PTx macros).
215
216local addrsize = "d" -- Size for address operands. !x64
217
218-- Helper function to fill register maps.
219local function mkrmap(sz, names)
220 for n,name in ipairs(names) do
221 local iname = format("@%s%x", sz, n-1)
222 reg_list[#reg_list+1] = iname
223 map_archdef[name] = iname
224 map_reg_rev[iname] = name
225 map_reg_num[iname] = n-1
226 map_reg_opsize[iname] = sz
227 if sz == addrsize then
228 map_reg_valid_base[iname] = true
229 map_reg_valid_index[iname] = true
230 end
231 end
232 reg_list[#reg_list+1] = ""
233end
234
235-- Integer registers (dword, word and byte sized).
236mkrmap("d", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})
237map_reg_valid_index[map_archdef.esp] = nil
238mkrmap("w", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})
239mkrmap("b", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})
240
241-- FP registers (internally tword sized, but use "f" as operand size).
242mkrmap("f", {"st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"})
243
244-- SSE registers (oword sized, but qword and dword accessible).
245mkrmap("o", {"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"})
246
247-- Operand size prefixes to codes.
248local map_opsize = {
249 byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t",
250 aword = addrsize,
251}
252
253-- Operand size code to number.
254local map_opsizenum = {
255 b = 1, w = 2, d = 4, q = 8, o = 16, t = 10,
256}
257
258-- Operand size code to name.
259local map_opsizename = {
260 b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword",
261 f = "fpword",
262}
263
264-- Valid index register scale factors.
265local map_xsc = {
266 ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,
267}
268
269-- Condition codes.
270local map_cc = {
271 o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7,
272 s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15,
273 c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7,
274 nge = 12, ge = 13, ng = 14, g = 15,
275}
276
277
278-- Reverse defines for registers.
279function _M.revdef(s)
280 return gsub(s, "@%w+", map_reg_rev)
281end
282
283-- Dump register names and numbers
284local function dumpregs(out)
285 out:write("Register names, sizes and internal numbers:\n")
286 for _,reg in ipairs(reg_list) do
287 if reg == "" then
288 out:write("\n")
289 else
290 local name = map_reg_rev[reg]
291 local num = map_reg_num[reg]
292 local opsize = map_opsizename[map_reg_opsize[reg]]
293 out:write(format(" %-5s %-8s %d\n", name, opsize, num))
294 end
295 end
296end
297
298------------------------------------------------------------------------------
299
300-- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).
301local function wputlabel(aprefix, imm, num)
302 if type(imm) == "number" then
303 waction(aprefix.."LG", nil, num);
304 wputxb(imm)
305 else
306 waction(aprefix.."PC", imm, num)
307 end
308end
309
310-- Put signed byte or arg.
311local function wputsbarg(n)
312 if type(n) == "number" then
313 if n < -128 or n > 127 then
314 werror("signed immediate byte out of range")
315 end
316 if n < 0 then n = n + 256 end
317 wputb(n)
318 else waction("IMM_S", n) end
319end
320
321-- Put unsigned byte or arg.
322local function wputbarg(n)
323 if type(n) == "number" then
324 if n < 0 or n > 255 then
325 werror("unsigned immediate byte out of range")
326 end
327 wputb(n)
328 else waction("IMM_B", n) end
329end
330
331-- Put unsigned word or arg.
332local function wputwarg(n)
333 if type(n) == "number" then
334 if n < 0 or n > 65535 then
335 werror("unsigned immediate word out of range")
336 end
337 local r = n%256; n = (n-r)/256; wputb(r); wputb(n);
338 else waction("IMM_W", n) end
339end
340
341-- Put signed or unsigned dword or arg.
342local function wputdarg(n)
343 local tn = type(n)
344 if tn == "number" then
345 if n < 0 then n = n + 4294967296 end
346 local r = n%256; n = (n-r)/256; wputb(r);
347 r = n%256; n = (n-r)/256; wputb(r);
348 r = n%256; n = (n-r)/256; wputb(r); wputb(n);
349 elseif tn == "table" then
350 wputlabel("IMM_", n[1], 1)
351 else
352 waction("IMM_D", n)
353 end
354end
355
356-- Put operand-size dependent number or arg (defaults to dword).
357local function wputszarg(sz, n)
358 if not sz or sz == "d" then wputdarg(n)
359 elseif sz == "w" then wputwarg(n)
360 elseif sz == "b" then wputbarg(n)
361 elseif sz == "s" then wputsbarg(n)
362 else werror("bad operand size") end
363end
364
365-- Put multi-byte opcode with operand-size dependent modifications.
366local function wputop(sz, op)
367 local r
368 if sz == "w" then wputb(102) end
369 if op >= 16777216 then r = op % 16777216 wputb((op-r) / 16777216) op = r end
370 if op >= 65536 then r = op % 65536 wputb((op-r) / 65536) op = r end
371 if op >= 256 then r = op % 256 wputb((op-r) / 256) op = r end
372 if sz == "b" then op = op - 1 end
373 wputb(op)
374end
375
376-- Put ModRM or SIB formatted byte.
377local function wputmodrm(m, s, rm)
378 assert(m < 4 and s < 8 and rm < 8, "bad modrm operands")
379 wputb(64*m + 8*s + rm)
380end
381
382-- Put ModRM/SIB plus optional displacement.
383local function wputmrmsib(t, s, imark)
384 -- Register mode.
385 if sub(t.mode, 1, 1) == "r" then
386 wputmodrm(3, s, t.reg)
387 return
388 end
389
390 local disp = t.disp
391 local tdisp = type(disp)
392 -- No base register?
393 if not t.reg then
394 if t.xreg then
395 -- Indexed mode with index register only.
396 wputmodrm(0, s, 4) -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
397 wputmodrm(t.xsc, t.xreg, 5)
398 else
399 -- Pure displacement.
400 wputmodrm(0, s, 5) -- [disp] -> (0, s, ebp)
401 end
402 wputdarg(disp)
403 return
404 end
405
406 local m
407 if tdisp == "number" then -- Check displacement size at assembly time.
408 if disp == 0 and t.reg ~= 5 then m = 0 -- [ebp] -> [ebp+0] (in SIB, too)
409 elseif disp >= -128 and disp <= 127 then m = 1
410 else m = 2 end
411 elseif tdisp == "table" then
412 m = 2
413 end
414
415 -- Index register present or esp as base register: need SIB encoding.
416 if t.xreg or t.reg == 4 then
417 wputmodrm(m or 2, s, 4) -- ModRM.
418 if (m == nil or imark) and tdisp ~= "table" then waction("MARK") end
419 wputmodrm(t.xsc or 0, t.xreg or 4, t.reg) -- SIB.
420 else
421 wputmodrm(m or 2, s, t.reg) -- ModRM.
422 if imark and (m == 1 or m == 2) then waction("MARK") end
423 end
424
425 -- Put displacement.
426 if m == 1 then wputsbarg(disp)
427 elseif m == 2 then wputdarg(disp)
428 elseif not m then waction("DISP", disp) end
429end
430
431------------------------------------------------------------------------------
432
433-- Return human-readable operand mode string.
434local function opmodestr(op, args)
435 local m = {}
436 for i=1,#args do
437 local a = args[i]
438 m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?")
439 end
440 return op.." "..concat(m, ",")
441end
442
443-- Convert number to valid integer or nil.
444local function toint(expr)
445 local n = tonumber(expr)
446 if n then
447 if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then
448 werror("bad integer number `"..expr.."'")
449 end
450 return n
451 end
452end
453
454-- Parse immediate expression.
455local function immexpr(expr)
456 -- &expr (pointer)
457 if sub(expr, 1, 1) == "&" then
458 return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2))
459 end
460
461 local prefix = sub(expr, 1, 2)
462 -- =>expr (pc label reference)
463 if prefix == "=>" then
464 return "iJ", sub(expr, 3)
465 end
466 -- ->name (global label reference)
467 if prefix == "->" then
468 return "iJ", map_global[sub(expr, 3)]
469 end
470
471 -- [<>][1-9] (local label reference)
472 local dir, lnum = match(expr, "^([<>])([1-9])$")
473 if dir then -- Fwd: 247-255, Bkwd: 1-9.
474 return "iJ", lnum + (dir == ">" and 246 or 0)
475 end
476
477 -- expr (interpreted as immediate)
478 return "iI", expr
479end
480
481-- Parse displacement expression: +-num, +-expr, +-opsize*num
482local function dispexpr(expr)
483 local disp = expr == "" and 0 or toint(expr)
484 if disp then return disp end
485 local c, dispt = match(expr, "^([+-])%s*(.+)$")
486 if c == "+" then
487 expr = dispt
488 elseif not c then
489 werror("bad displacement expression `"..expr.."'")
490 end
491 local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$")
492 local ops, imm = map_opsize[opsize], toint(tailops)
493 if ops and imm then
494 if c == "-" then imm = -imm end
495 return imm*map_opsizenum[ops]
496 end
497 local mode, iexpr = immexpr(dispt)
498 if mode == "iJ" then
499 if c == "-" then werror("cannot invert label reference") end
500 return { iexpr }
501 end
502 return expr -- Need to return original signed expression.
503end
504
505-- Parse register or type expression.
506local function rtexpr(expr)
507 if not expr then return end
508 local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$")
509 local tp = map_type[tname or expr]
510 if tp then
511 local reg = ovreg or tp.reg
512 local rnum = map_reg_num[reg]
513 if not rnum then
514 werror("type `"..(tname or expr).."' needs a register override")
515 end
516 if not map_reg_valid_base[reg] then
517 werror("bad base register override `"..(map_reg_rev[reg] or reg).."'")
518 end
519 return reg, rnum, tp
520 end
521 return expr, map_reg_num[expr]
522end
523
524-- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }.
525local function parseoperand(param)
526 local t = {}
527
528 local expr = param
529 local opsize, tailops = match(param, "^(%w+)%s*(.+)$")
530 if opsize then
531 t.opsize = map_opsize[opsize]
532 if t.opsize then expr = tailops end
533 end
534
535 local br = match(expr, "^%[%s*(.-)%s*%]$")
536 repeat
537 if br then
538 t.mode = "xm"
539
540 -- [disp]
541 t.disp = toint(br)
542 if t.disp then
543 t.mode = "xmO"
544 break
545 end
546
547 -- [reg...]
548 local tp
549 local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$")
550 reg, t.reg, tp = rtexpr(reg)
551 if not t.reg then
552 -- [expr]
553 t.mode = "xmO"
554 t.disp = dispexpr("+"..br)
555 break
556 end
557
558 -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr]
559 local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$")
560 if xsc then
561 if not map_reg_valid_index[reg] then
562 werror("bad index register `"..map_reg_rev[reg].."'")
563 end
564 t.xsc = map_xsc[xsc]
565 t.xreg = t.reg
566 t.reg = nil
567 t.disp = dispexpr(tailsc)
568 break
569 end
570 if not map_reg_valid_base[reg] then
571 werror("bad base register `"..map_reg_rev[reg].."'")
572 end
573
574 -- [reg] or [reg+-disp]
575 t.disp = toint(tailr) or (tailr == "" and 0)
576 if t.disp then break end
577
578 -- [reg+xreg...]
579 local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$")
580 xreg, t.xreg, tp = rtexpr(xreg)
581 if not t.xreg then
582 -- [reg+-expr]
583 t.disp = dispexpr(tailr)
584 break
585 end
586 if not map_reg_valid_index[xreg] then
587 werror("bad index register `"..map_reg_rev[xreg].."'")
588 end
589
590 -- [reg+xreg*xsc...]
591 local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$")
592 if xsc then
593 t.xsc = map_xsc[xsc]
594 tailx = tailsc
595 end
596
597 -- [...] or [...+-disp] or [...+-expr]
598 t.disp = dispexpr(tailx)
599 else
600 -- imm or opsize*imm
601 local imm = toint(expr)
602 if not imm and sub(expr, 1, 1) == "*" and t.opsize then
603 imm = toint(sub(expr, 2))
604 if imm then
605 imm = imm * map_opsizenum[t.opsize]
606 t.opsize = nil
607 end
608 end
609 if imm then
610 if t.opsize then werror("bad operand size override") end
611 local m = "i"
612 if imm == 1 then m = m.."1" end
613 if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end
614 if imm >= -128 and imm <= 127 then m = m.."S" end
615 t.imm = imm
616 t.mode = m
617 break
618 end
619
620 local tp
621 local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$")
622 reg, t.reg, tp = rtexpr(reg)
623 if t.reg then
624 -- reg
625 if tailr == "" then
626 if t.opsize then werror("bad operand size override") end
627 t.opsize = map_reg_opsize[reg]
628 if t.opsize == "f" then
629 t.mode = t.reg == 0 and "fF" or "f"
630 else
631 if reg == "@w4" then wwarn("bad idea, try again with `esp'") end
632 t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm")
633 end
634 break
635 end
636
637 -- type[idx], type[idx].field, type->field -> [reg+offset_expr]
638 if not tp then werror("bad operand `"..param.."'") end
639 t.mode = "xm"
640 t.disp = format(tp.ctypefmt, tailr)
641 else
642 t.mode, t.imm = immexpr(expr)
643 if sub(t.mode, -1) == "J" then
644 if t.opsize and t.opsize ~= addrsize then
645 werror("bad operand size override")
646 end
647 t.opsize = addrsize
648 end
649 end
650 end
651 until true
652 return t
653end
654
655------------------------------------------------------------------------------
656-- x86 Template String Description
657-- ===============================
658--
659-- Each template string is a list of [match:]pattern pairs,
660-- separated by "|". The first match wins. No match means a
661-- bad or unsupported combination of operand modes or sizes.
662--
663-- The match part and the ":" is omitted if the operation has
664-- no operands. Otherwise the first N characters are matched
665-- against the mode strings of each of the N operands.
666--
667-- The mode string for each operand type is (see parseoperand()):
668-- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl
669-- FP register: "f", +"F" for st0
670-- Index operand: "xm", +"O" for [disp] (pure offset)
671-- Immediate: "i", +"S" for signed 8 bit, +"1" for 1,
672-- +"I" for arg, +"P" for pointer
673-- Any: +"J" for valid jump targets
674--
675-- So a match character "m" (mixed) matches both an integer register
676-- and an index operand (to be encoded with the ModRM/SIB scheme).
677-- But "r" matches only a register and "x" only an index operand
678-- (e.g. for FP memory access operations).
679--
680-- The operand size match string starts right after the mode match
681-- characters and ends before the ":". "dwb" is assumed, if empty.
682-- The effective data size of the operation is matched against this list.
683--
684-- If only the regular "b", "w", "d", "q", "t" operand sizes are
685-- present, then all operands must be the same size. Unspecified sizes
686-- are ignored, but at least one operand must have a size or the pattern
687-- won't match (use the "byte", "word", "dword", "qword", "tword"
688-- operand size overrides. E.g.: mov dword [eax], 1).
689--
690-- If the list has a "1" or "2" prefix, the operand size is taken
691-- from the respective operand and any other operand sizes are ignored.
692-- If the list contains only ".", all operand sizes are ignored.
693-- If the list has a "/" prefix, the concatenated (mixed) operand sizes
694-- are compared to the match.
695--
696-- E.g. "rrdw" matches for either two dword registers or two word
697-- registers. "Fx2dq" matches an st0 operand plus an index operand
698-- pointing to a dword (float) or qword (double).
699--
700-- Every character after the ":" is part of the pattern string:
701-- Hex chars are accumulated to form the opcode (left to right).
702-- "n" disables the standard opcode mods
703-- (otherwise: -1 for "b", o16 prefix for "w")
704-- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode.
705-- "m"/"M" generates ModRM/SIB from the 1st/2nd operand.
706-- The spare 3 bits are either filled with the last hex digit or
707-- the result from a previous "r"/"R". The opcode is restored.
708--
709-- All of the following characters force a flush of the opcode:
710-- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand.
711-- "S" stores a signed 8 bit immediate from the last operand.
712-- "U" stores an unsigned 8 bit immediate from the last operand.
713-- "W" stores an unsigned 16 bit immediate from the last operand.
714-- "i" stores an operand sized immediate from the last operand.
715-- "I" dito, but generates an action code to optionally modify
716-- the opcode (+2) for a signed 8 bit immediate.
717-- "J" generates one of the REL action codes from the last operand.
718--
719------------------------------------------------------------------------------
720
721-- Template strings for x86 instructions. Ordered by first opcode byte.
722-- Unimplemented opcodes (deliberate omissions) are marked with *.
723local map_op = {
724 -- 00-05: add...
725 -- 06: *push es
726 -- 07: *pop es
727 -- 08-0D: or...
728 -- 0E: *push cs
729 -- 0F: two byte opcode prefix
730 -- 10-15: adc...
731 -- 16: *push ss
732 -- 17: *pop ss
733 -- 18-1D: sbb...
734 -- 1E: *push ds
735 -- 1F: *pop ds
736 -- 20-25: and...
737 es_0 = "26",
738 -- 27: *daa
739 -- 28-2D: sub...
740 cs_0 = "2E",
741 -- 2F: *das
742 -- 30-35: xor...
743 ss_0 = "36",
744 -- 37: *aaa
745 -- 38-3D: cmp...
746 ds_0 = "3E",
747 -- 3F: *aas
748 inc_1 = "rdw:40r|m:FF0m",
749 dec_1 = "rdw:48r|m:FF1m",
750 push_1 = "rdw:50r|mdw:FF6m|S.:6AS|ib:n6Ai|i.:68i",
751 pop_1 = "rdw:58r|mdw:8F0m",
752 -- 60: *pusha, *pushad, *pushaw
753 -- 61: *popa, *popad, *popaw
754 -- 62: *bound rdw,x
755 -- 63: *arpl mw,rw
756 fs_0 = "64",
757 gs_0 = "65",
758 o16_0 = "66",
759 a16_0 = "67",
760 -- 68: push idw
761 -- 69: imul rdw,mdw,idw
762 -- 6A: push ib
763 -- 6B: imul rdw,mdw,S
764 -- 6C: *insb
765 -- 6D: *insd, *insw
766 -- 6E: *outsb
767 -- 6F: *outsd, *outsw
768 -- 70-7F: jcc lb
769 -- 80: add... mb,i
770 -- 81: add... mdw,i
771 -- 82: *undefined
772 -- 83: add... mdw,S
773 test_2 = "mr:85Rm|rm:85rM|Ri:A9i|mi:F70mi",
774 -- 86: xchg rb,mb
775 -- 87: xchg rdw,mdw
776 -- 88: mov mb,r
777 -- 89: mov mdw,r
778 -- 8A: mov r,mb
779 -- 8B: mov r,mdw
780 -- 8C: *mov mdw,seg
781 lea_2 = "rxd:8DrM",
782 -- 8E: *mov seg,mdw
783 -- 8F: pop mdw
784 nop_0 = "90",
785 xchg_2 = "Rrdw:90R|rRdw:90r|rm:87rM|mr:87Rm",
786 cbw_0 = "6698",
787 cwde_0 = "98",
788 cwd_0 = "6699",
789 cdq_0 = "99",
790 -- 9A: *call iw:idw
791 wait_0 = "9B",
792 fwait_0 = "9B",
793 pushf_0 = "9C",
794 pushfw_0 = "669C",
795 pushfd_0 = "9C",
796 popf_0 = "9D",
797 popfw_0 = "669D",
798 popfd_0 = "9D",
799 sahf_0 = "9E",
800 lahf_0 = "9F",
801 mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi",
802 movsb_0 = "A4",
803 movsw_0 = "66A5",
804 movsd_0 = "A5",
805 cmpsb_0 = "A6",
806 cmpsw_0 = "66A7",
807 cmpsd_0 = "A7",
808 -- A8: test Rb,i
809 -- A9: test Rdw,i
810 stosb_0 = "AA",
811 stosw_0 = "66AB",
812 stosd_0 = "AB",
813 lodsb_0 = "AC",
814 lodsw_0 = "66AD",
815 lodsd_0 = "AD",
816 scasb_0 = "AE",
817 scasw_0 = "66AF",
818 scasd_0 = "AF",
819 -- B0-B7: mov rb,i
820 -- B8-BF: mov rdw,i
821 -- C0: rol... mb,i
822 -- C1: rol... mdw,i
823 ret_1 = "i.:nC2W",
824 ret_0 = "C3",
825 -- C4: *les rdw,mq
826 -- C5: *lds rdw,mq
827 -- C6: mov mb,i
828 -- C7: mov mdw,i
829 -- C8: *enter iw,ib
830 leave_0 = "C9",
831 -- CA: *retf iw
832 -- CB: *retf
833 int3_0 = "CC",
834 int_1 = "i.:nCDU",
835 into_0 = "CE",
836 -- CF: *iret
837 -- D0: rol... mb,1
838 -- D1: rol... mdw,1
839 -- D2: rol... mb,cl
840 -- D3: rol... mb,cl
841 -- D4: *aam ib
842 -- D5: *aad ib
843 -- D6: *salc
844 -- D7: *xlat
845 -- D8-DF: floating point ops
846 -- E0: *loopne
847 -- E1: *loope
848 -- E2: *loop
849 -- E3: *jcxz, *jecxz
850 -- E4: *in Rb,ib
851 -- E5: *in Rdw,ib
852 -- E6: *out ib,Rb
853 -- E7: *out ib,Rdw
854 call_1 = "md:FF2m|J.:E8J",
855 jmp_1 = "md:FF4m|J.:E9J", -- short: EB
856 -- EA: *jmp iw:idw
857 -- EB: jmp ib
858 -- EC: *in Rb,dx
859 -- ED: *in Rdw,dx
860 -- EE: *out dx,Rb
861 -- EF: *out dx,Rdw
862 -- F0: *lock
863 int1_0 = "F1",
864 repne_0 = "F2",
865 repnz_0 = "F2",
866 rep_0 = "F3",
867 repe_0 = "F3",
868 repz_0 = "F3",
869 -- F4: *hlt
870 cmc_0 = "F5",
871 -- F6: test... mb,i; div... mb
872 -- F7: test... mdw,i; div... mdw
873 clc_0 = "F8",
874 stc_0 = "F9",
875 -- FA: *cli
876 cld_0 = "FC",
877 std_0 = "FD",
878 -- FE: inc... mb
879 -- FF: inc... mdw
880
881 -- misc ops
882 not_1 = "m:F72m",
883 neg_1 = "m:F73m",
884 mul_1 = "m:F74m",
885 imul_1 = "m:F75m",
886 div_1 = "m:F76m",
887 idiv_1 = "m:F77m",
888
889 imul_2 = "rmdw:0FAFrM|rIdw:69rmI|rSdw:6BrmS|ridw:69rmi",
890 imul_3 = "rmIdw:69rMI|rmSdw:6BrMS|rmidw:69rMi",
891
892 movzx_2 = "rm/db:0FB6rM|rm/wb:0FB6rM|rm/dw:0FB7rM",
893 movsx_2 = "rm/db:0FBErM|rm/wb:0FBErM|rm/dw:0FBFrM",
894
895 bswap_1 = "rd:0FC8r",
896 bsf_2 = "rmdw:0FBCrM",
897 bsr_2 = "rmdw:0FBDrM",
898 bt_2 = "mrdw:0FA3Rm|midw:0FBA4mU",
899 btc_2 = "mrdw:0FBBRm|midw:0FBA7mU",
900 btr_2 = "mrdw:0FB3Rm|midw:0FBA6mU",
901 bts_2 = "mrdw:0FABRm|midw:0FBA5mU",
902
903 rdtsc_0 = "0F31", -- P1+
904 cpuid_0 = "0FA2", -- P1+
905
906 -- floating point ops
907 fst_1 = "ff:DDD0r|xd:D92m|xq:DD2m",
908 fstp_1 = "ff:DDD8r|xd:D93m|xq:DD3m|xt:DB7m",
909 fld_1 = "ff:D9C0r|xd:D90m|xq:DD0m|xt:DB5m",
910
911 fpop_0 = "DDD8", -- Alias for fstp st0.
912
913 fist_1 = "xw:nDF2m|xd:DB2m",
914 fistp_1 = "xw:nDF3m|xd:DB3m|xq:DF7m",
915 fisttp_1 = "xw:nDF1m|xd:DB1m|xq:DD1m", -- SSE3
916 fild_1 = "xw:nDF0m|xd:DB0m|xq:DF5m",
917
918 fxch_0 = "D9C9",
919 fxch_1 = "ff:D9C8r",
920 fxch_2 = "fFf:D9C8r|Fff:D9C8R",
921
922 fucom_1 = "ff:DDE0r",
923 fucom_2 = "Fff:DDE0R",
924 fucomp_1 = "ff:DDE8r",
925 fucomp_2 = "Fff:DDE8R",
926 fucomi_1 = "ff:DBE8r", -- P6+
927 fucomi_2 = "Fff:DBE8R", -- P6+
928 fucomip_1 = "ff:DFE8r", -- P6+
929 fucomip_2 = "Fff:DFE8R", -- P6+
930 fcomi_1 = "ff:DBF0r", -- P6+
931 fcomi_2 = "Fff:DBF0R", -- P6+
932 fcomip_1 = "ff:DFF0r", -- P6+
933 fcomip_2 = "Fff:DFF0R", -- P6+
934 fucompp_0 = "DAE9",
935 fcompp_0 = "DED9",
936
937 fldcw_1 = "xw:nD95m",
938 fstcw_1 = "xw:n9BD97m",
939 fnstcw_1 = "xw:nD97m",
940 fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m",
941 fnstsw_1 = "Rw:nDFE0|xw:nDD7m",
942 fclex_0 = "9BDBE2",
943 fnclex_0 = "DBE2",
944
945 fnop_0 = "D9D0",
946 -- D9D1-D9DF: unassigned
947
948 fchs_0 = "D9E0",
949 fabs_0 = "D9E1",
950 -- D9E2: unassigned
951 -- D9E3: unassigned
952 ftst_0 = "D9E4",
953 fxam_0 = "D9E5",
954 -- D9E6: unassigned
955 -- D9E7: unassigned
956 fld1_0 = "D9E8",
957 fldl2t_0 = "D9E9",
958 fldl2e_0 = "D9EA",
959 fldpi_0 = "D9EB",
960 fldlg2_0 = "D9EC",
961 fldln2_0 = "D9ED",
962 fldz_0 = "D9EE",
963 -- D9EF: unassigned
964
965 f2xm1_0 = "D9F0",
966 fyl2x_0 = "D9F1",
967 fptan_0 = "D9F2",
968 fpatan_0 = "D9F3",
969 fxtract_0 = "D9F4",
970 fprem1_0 = "D9F5",
971 fdecstp_0 = "D9F6",
972 fincstp_0 = "D9F7",
973 fprem_0 = "D9F8",
974 fyl2xp1_0 = "D9F9",
975 fsqrt_0 = "D9FA",
976 fsincos_0 = "D9FB",
977 frndint_0 = "D9FC",
978 fscale_0 = "D9FD",
979 fsin_0 = "D9FE",
980 fcos_0 = "D9FF",
981
982 -- SSE, SSE2, SSE3, SSSE3 ops
983 addsubpd_2 = "rmo:660FD0rM",
984 addsubps_2 = "rmo:F20FD0rM",
985 andnpd_2 = "rmo:660F55rM",
986 andnps_2 = "rmo:0F55rM",
987 andpd_2 = "rmo:660F54rM",
988 andps_2 = "rmo:0F54rM",
989 clflush_1 = "x.:0FAE7m",
990 cmppd_3 = "rmio:660FC2rMU",
991 cmpps_3 = "rmio:0FC2rMU",
992 cmpsd_3 = "rmio:F20FC2rMU",
993 cmpss_3 = "rmio:F30FC2rMU",
994 comisd_2 = "rmo:660F2FrM",
995 comiss_2 = "rmo:0F2FrM",
996 cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:",
997 cvtdq2ps_2 = "rmo:0F5BrM",
998 cvtpd2dq_2 = "rmo:F20FE6rM",
999 cvtpd2ps_2 = "rmo:660F5ArM",
1000 cvtpi2pd_2 = "rx/oq:660F2ArM",
1001 cvtpi2ps_2 = "rx/oq:0F2ArM",
1002 cvtps2dq_2 = "rmo:660F5BrM",
1003 cvtps2pd_2 = "rro:0F5ArM|rx/oq:",
1004 cvtsd2si_2 = "rr/do:F20F2DrM|rx/dq:",
1005 cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:",
1006 cvtsi2sd_2 = "rm/od:F20F2ArM",
1007 cvtsi2ss_2 = "rm/od:F30F2ArM",
1008 cvtss2sd_2 = "rro:F30F5ArM|rx/od:",
1009 cvtss2si_2 = "rr/do:F20F2CrM|rx/dd:",
1010 cvttpd2dq_2 = "rmo:660FE6rM",
1011 cvttps2dq_2 = "rmo:F30F5BrM",
1012 cvttsd2si_2 = "rr/do:F20F2CrM|rx/dq:",
1013 cvttss2si_2 = "rr/do:F30F2CrM|rx/dd:",
1014 haddpd_2 = "rmo:660F7CrM",
1015 haddps_2 = "rmo:F20F7CrM",
1016 hsubpd_2 = "rmo:660F7DrM",
1017 hsubps_2 = "rmo:F20F7DrM",
1018 lddqu_2 = "rxo:F20FF0rM",
1019 ldmxcsr_1 = "xd:0FAE2m",
1020 lfence_0 = "0FAEE8",
1021 maskmovdqu_2 = "rro:660FF7rM",
1022 mfence_0 = "0FAEF0",
1023 movapd_2 = "rmo:660F28rM|mro:660F29Rm",
1024 movaps_2 = "rmo:0F28rM|mro:0F29Rm",
1025 movd_2 = "rm/od:660F6ErM|mr/do:660F7ERm",
1026 movddup_2 = "rmo:F20F12rM",
1027 movdqa_2 = "rmo:660F6FrM|mro:660F7FRm",
1028 movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm",
1029 movhlps_2 = "rro:0F12rM",
1030 movhpd_2 = "rx/oq:660F16rM|xr/qo:660F17Rm",
1031 movhps_2 = "rx/oq:0F16rM|xr/qo:0F17Rm",
1032 movlhps_2 = "rro:0F16rM",
1033 movlpd_2 = "rx/oq:660F12rM|xr/qo:660F13Rm",
1034 movlps_2 = "rx/oq:0F12rM|xr/qo:0F13Rm",
1035 movmskpd_2 = "rr/do:660F50rM",
1036 movmskps_2 = "rr/do:0F50rM",
1037 movntdq_2 = "xro:660FE7Rm",
1038 movnti_2 = "xrd:0FC3Rm",
1039 movntpd_2 = "xro:660F2BRm",
1040 movntps_2 = "xro:0F2BRm",
1041 movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:660FD6Rm",
1042 movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:F20F11Rm",
1043 movshdup_2 = "rmo:F30F16rM",
1044 movsldup_2 = "rmo:F30F12rM",
1045 movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm",
1046 movupd_2 = "rmo:660F10rM|mro:660F11Rm",
1047 movups_2 = "rmo:0F10rM|mro:0F11Rm",
1048 orpd_2 = "rmo:660F56rM",
1049 orps_2 = "rmo:0F56rM",
1050 pabsb_2 = "rmo:660F381CrM",
1051 pabsd_2 = "rmo:660F381ErM",
1052 pabsw_2 = "rmo:660F381DrM",
1053 packssdw_2 = "rmo:660F6BrM",
1054 packsswb_2 = "rmo:660F63rM",
1055 packuswb_2 = "rmo:660F67rM",
1056 paddb_2 = "rmo:660FFCrM",
1057 paddd_2 = "rmo:660FFErM",
1058 paddq_2 = "rmo:660FD4rM",
1059 paddsb_2 = "rmo:660FECrM",
1060 paddsw_2 = "rmo:660FEDrM",
1061 paddusb_2 = "rmo:660FDCrM",
1062 paddusw_2 = "rmo:660FDDrM",
1063 paddw_2 = "rmo:660FFDrM",
1064 palignr_3 = "rmio:660F3A0FrMU",
1065 pand_2 = "rmo:660FDBrM",
1066 pandn_2 = "rmo:660FDFrM",
1067 pause_0 = "F390",
1068 pavgb_2 = "rmo:660FE0rM",
1069 pavgw_2 = "rmo:660FE3rM",
1070 pcmpeqb_2 = "rmo:660F74rM",
1071 pcmpeqd_2 = "rmo:660F76rM",
1072 pcmpeqw_2 = "rmo:660F75rM",
1073 pcmpgtb_2 = "rmo:660F64rM",
1074 pcmpgtd_2 = "rmo:660F66rM",
1075 pcmpgtw_2 = "rmo:660F65rM",
1076 pextrw_3 = "rri/do:660FC5rMU",
1077 phaddd_2 = "rmo:660F3802rM",
1078 phaddsw_2 = "rmo:660F3803rM",
1079 phaddw_2 = "rmo:660F3801rM",
1080 phsubd_2 = "rmo:660F3806rM",
1081 phsubsw_2 = "rmo:660F3807rM",
1082 phsubw_2 = "rmo:660F3805rM",
1083 pinsrw_3 = "rri/od:660FC4rMU|rmi/ow:",
1084 pmaddubsw_2 = "rmo:660F3804rM",
1085 pmaddwd_2 = "rmo:660FF5rM",
1086 pmaxsw_2 = "rmo:660FEErM",
1087 pmaxub_2 = "rmo:660FDErM",
1088 pminsw_2 = "rmo:660FEArM",
1089 pminub_2 = "rmo:660FDArM",
1090 pmovmskb_2 = "rr/do:660FD7rM",
1091 pmulhrsw_2 = "rmo:660F380BrM",
1092 pmulhuw_2 = "rmo:660FE4rM",
1093 pmulhw_2 = "rmo:660FE5rM",
1094 pmullw_2 = "rmo:660FD5rM",
1095 pmuludq_2 = "rmo:660FF4rM",
1096 por_2 = "rmo:660FEBrM",
1097 prefetchnta_1 = "xb:n0F180m",
1098 prefetcht0_1 = "xb:n0F181m",
1099 prefetcht1_1 = "xb:n0F182m",
1100 prefetcht2_1 = "xb:n0F183m",
1101 psadbw_2 = "rmo:660FF6rM",
1102 pshufb_2 = "rmo:660F3800rM",
1103 pshufd_3 = "rmio:660F70rMU",
1104 pshufhw_3 = "rmio:F30F70rMU",
1105 pshuflw_3 = "rmio:F20F70rMU",
1106 psignb_2 = "rmo:660F3808rM",
1107 psignd_2 = "rmo:660F380ArM",
1108 psignw_2 = "rmo:660F3809rM",
1109 pslld_2 = "rmo:660FF2rM|rio:660F726mU",
1110 pslldq_2 = "rio:660F737mU",
1111 psllq_2 = "rmo:660FF3rM|rio:660F736mU",
1112 psllw_2 = "rmo:660FF1rM|rio:660F716mU",
1113 psrad_2 = "rmo:660FE2rM|rio:660F724mU",
1114 psraw_2 = "rmo:660FE1rM|rio:660F714mU",
1115 psrld_2 = "rmo:660FD2rM|rio:660F722mU",
1116 psrldq_2 = "rio:660F733mU",
1117 psrlq_2 = "rmo:660FD3rM|rio:660F732mU",
1118 psrlw_2 = "rmo:660FD1rM|rio:660F712mU",
1119 psubb_2 = "rmo:660FF8rM",
1120 psubd_2 = "rmo:660FFArM",
1121 psubq_2 = "rmo:660FFBrM",
1122 psubsb_2 = "rmo:660FE8rM",
1123 psubsw_2 = "rmo:660FE9rM",
1124 psubusb_2 = "rmo:660FD8rM",
1125 psubusw_2 = "rmo:660FD9rM",
1126 psubw_2 = "rmo:660FF9rM",
1127 punpckhbw_2 = "rmo:660F68rM",
1128 punpckhdq_2 = "rmo:660F6ArM",
1129 punpckhqdq_2 = "rmo:660F6DrM",
1130 punpckhwd_2 = "rmo:660F69rM",
1131 punpcklbw_2 = "rmo:660F60rM",
1132 punpckldq_2 = "rmo:660F62rM",
1133 punpcklqdq_2 = "rmo:660F6CrM",
1134 punpcklwd_2 = "rmo:660F61rM",
1135 pxor_2 = "rmo:660FEFrM",
1136 rcpps_2 = "rmo:0F53rM",
1137 rcpss_2 = "rmo:F30F53rM",
1138 rsqrtps_2 = "rmo:0F52rM",
1139 rsqrtss_2 = "rmo:F30F52rM",
1140 sfence_0 = "0FAEF8",
1141 shufpd_3 = "rmio:660FC6rMU",
1142 shufps_3 = "rmio:0FC6rMU",
1143 stmxcsr_1 = "xd:0FAE3m",
1144 ucomisd_2 = "rmo:660F2ErM",
1145 ucomiss_2 = "rmo:0F2ErM",
1146 unpckhpd_2 = "rmo:660F15rM",
1147 unpckhps_2 = "rmo:0F15rM",
1148 unpcklpd_2 = "rmo:660F14rM",
1149 unpcklps_2 = "rmo:0F14rM",
1150 xorpd_2 = "rmo:660F57rM",
1151 xorps_2 = "rmo:0F57rM",
1152}
1153
1154------------------------------------------------------------------------------
1155
1156-- Arithmetic ops.
1157for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3,
1158 ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do
1159 local n8 = n * 8
1160 map_op[name.."_2"] = format(
1161 "mr:%02XRm|rm:%02XrM|mI1dw:81%XmI|mS1dw:83%XmS|Ri1dwb:%02Xi|mi1dwb:81%Xmi",
1162 1+n8, 3+n8, n, n, 5+n8, n)
1163end
1164
1165-- Shift ops.
1166for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3,
1167 shl = 4, shr = 5, sar = 7, sal = 4 } do
1168 map_op[name.."_2"] = format("m1:D1%Xm|mC1dwb:D3%Xm|mi:C1%XmU", n, n, n)
1169end
1170
1171-- Conditional ops.
1172for cc,n in pairs(map_cc) do
1173 map_op["j"..cc.."_1"] = format("J.:0F8%XJ", n) -- short: 7%X
1174 map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n)
1175 map_op["cmov"..cc.."_2"] = format("rmdw:0F4%XrM", n) -- P6+
1176end
1177
1178-- FP arithmetic ops.
1179for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3,
1180 sub = 4, subr = 5, div = 6, divr = 7 } do
1181 local nc = 192 + n * 8
1182 local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8))
1183 local fn = "f"..name
1184 map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:DC%Xm", nc, n, n)
1185 if n == 2 or n == 3 then
1186 map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:DC%XM", nc, n, n)
1187 else
1188 map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:DC%XM", nc, nr, n, n)
1189 map_op[fn.."p_1"] = format("ff:DE%02Xr", nr)
1190 map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr)
1191 end
1192 map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n)
1193end
1194
1195-- FP conditional moves.
1196for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do
1197 local n4 = n % 4
1198 local nc = 56000 + n4 * 8 + (n-n4) * 64
1199 map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+
1200 map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+
1201end
1202
1203-- SSE FP arithmetic ops.
1204for name,n in pairs{ sqrt = 1, add = 8, mul = 9,
1205 sub = 12, min = 13, div = 14, max = 15 } do
1206 map_op[name.."ps_2"] = format("rmo:0F5%XrM", n)
1207 map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n)
1208 map_op[name.."pd_2"] = format("rmo:660F5%XrM", n)
1209 map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n)
1210end
1211
1212------------------------------------------------------------------------------
1213
1214-- Process pattern string.
1215local function dopattern(pat, args, sz, op)
1216 local digit, addin
1217 local opcode = 0
1218 local szov = sz
1219
1220 -- Limit number of section buffer positions used by a single dasm_put().
1221 -- A single opcode needs a maximum of 2 positions. !x64
1222 if secpos+2 > maxsecpos then wflush() end
1223
1224 -- Process each character.
1225 for c in gmatch(pat, ".") do
1226 if match(c, "%x") then -- Hex digit.
1227 digit = byte(c) - 48
1228 if digit > 48 then digit = digit - 39
1229 elseif digit > 16 then digit = digit - 7 end
1230 opcode = opcode*16 + digit
1231 addin = nil
1232 elseif c == "n" then -- Disable operand size mods for opcode.
1233 szov = nil
1234 elseif c == "r" then -- Merge 1st operand regno. into opcode.
1235 addin = args[1].reg; opcode = opcode + addin
1236 elseif c == "R" then -- Merge 2nd operand regno. into opcode.
1237 addin = args[2].reg; opcode = opcode + addin
1238 elseif c == "m" or c == "M" then -- Encode ModRM/SIB.
1239 if addin then
1240 opcode = opcode - addin -- Undo regno opcode merge.
1241 else
1242 addin = opcode % 16 -- Undo last digit.
1243 opcode = (opcode - addin) / 16
1244 end
1245 wputop(szov, opcode); opcode = nil
1246 local imark = (sub(pat, -1) == "I") -- Force a mark (ugly).
1247 -- Put ModRM/SIB with regno/last digit as spare.
1248 wputmrmsib(args[c == "m" and 1 or 2], addin, imark)
1249 else
1250 if opcode then wputop(szov, opcode); opcode = nil end -- Flush opcode.
1251 if c == "o" or c == "O" then -- Offset (pure 32 bit displacement).
1252 wputdarg(args[c == "o" and 1 or 2].disp)
1253 else
1254 -- Anything else is an immediate operand.
1255 local a = args[#args]
1256 local mode, imm = a.mode, a.imm
1257 if mode == "iJ" and not match("iIJ", c) then
1258 werror("bad operand size for label")
1259 end
1260 if c == "S" then
1261 wputsbarg(imm)
1262 elseif c == "U" then
1263 wputbarg(imm)
1264 elseif c == "W" then
1265 wputwarg(imm)
1266 elseif c == "i" or c == "I" then
1267 if mode == "iJ" then
1268 wputlabel("IMM_", imm, 1)
1269 elseif mode == "iI" and c == "I" then
1270 waction(sz == "w" and "IMM_WB" or "IMM_DB", imm)
1271 else
1272 wputszarg(sz, imm)
1273 end
1274 elseif c == "J" then
1275 if mode == "iPJ" then
1276 waction("REL_A", imm) -- !x64 (secpos)
1277 else
1278 wputlabel("REL_", imm, 2)
1279 end
1280 else
1281 werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'")
1282 end
1283 end
1284 end
1285 end
1286 if opcode then wputop(szov, opcode) end
1287end
1288
1289------------------------------------------------------------------------------
1290
1291-- Mapping of operand modes to short names. Suppress output with '#'.
1292local map_modename = {
1293 r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm",
1294 f = "stx", F = "st0", J = "lbl", ["1"] = "1",
1295 I = "#", S = "#", O = "#",
1296}
1297
1298-- Return a table/string showing all possible operand modes.
1299local function templatehelp(template, nparams)
1300 if nparams == 0 then return "" end
1301 local t = {}
1302 for tm in gmatch(template, "[^%|]+") do
1303 local s = map_modename[sub(tm, 1, 1)]
1304 s = s..gsub(sub(tm, 2, nparams), ".", function(c)
1305 return ", "..map_modename[c]
1306 end)
1307 if not match(s, "#") then t[#t+1] = s end
1308 end
1309 return t
1310end
1311
1312-- Match operand modes against mode match part of template.
1313local function matchtm(tm, args)
1314 for i=1,#args do
1315 if not match(args[i].mode, sub(tm, i, i)) then return end
1316 end
1317 return true
1318end
1319
1320-- Handle opcodes defined with template strings.
1321map_op[".template__"] = function(params, template, nparams)
1322 if not params then return templatehelp(template, nparams) end
1323 local args = {}
1324
1325 -- Zero-operand opcodes have no match part.
1326 if #params == 0 then
1327 dopattern(template, args, "d", params.op)
1328 return
1329 end
1330
1331 -- Determine common operand size (coerce undefined size) or flag as mixed.
1332 local sz, szmix
1333 for i,p in ipairs(params) do
1334 args[i] = parseoperand(p)
1335 local nsz = args[i].opsize
1336 if nsz then
1337 if sz and sz ~= nsz then szmix = true else sz = nsz end
1338 end
1339 end
1340
1341 -- Try all match:pattern pairs (separated by '|').
1342 local gotmatch, lastpat
1343 for tm in gmatch(template, "[^%|]+") do
1344 -- Split off size match (starts after mode match) and pattern string.
1345 local szm, pat = match(tm, "^(.-):(.*)$", #args+1)
1346 if pat == "" then pat = lastpat else lastpat = pat end
1347 if matchtm(tm, args) then
1348 local prefix = sub(szm, 1, 1)
1349 if prefix == "/" then -- Match both operand sizes.
1350 if args[1].opsize == sub(szm, 2, 2) and
1351 args[2].opsize == sub(szm, 3, 3) then
1352 dopattern(pat, args, sz, params.op) -- Process pattern string.
1353 return
1354 end
1355 else -- Match common operand size.
1356 local szp = sz
1357 if szm == "" then szm = "dwb" end -- Default size match.
1358 if prefix == "1" then szp = args[1].opsize; szmix = nil
1359 elseif prefix == "2" then szp = args[2].opsize; szmix = nil end
1360 if not szmix and (prefix == "." or match(szm, szp or "#")) then
1361 dopattern(pat, args, szp, params.op) -- Process pattern string.
1362 return
1363 end
1364 end
1365 gotmatch = true
1366 end
1367 end
1368
1369 local msg = "bad operand mode"
1370 if gotmatch then
1371 if szmix then
1372 msg = "mixed operand size"
1373 else
1374 msg = sz and "bad operand size" or "missing operand size"
1375 end
1376 end
1377
1378 werror(msg.." in `"..opmodestr(params.op, args).."'")
1379end
1380
1381------------------------------------------------------------------------------
1382
1383-- Pseudo-opcodes for data storage.
1384local function op_data(params)
1385 if not params then return "imm..." end
1386 local sz = sub(params.op, 2, 2)
1387 if sz == "a" then sz = addrsize end
1388 for _,p in ipairs(params) do
1389 local a = parseoperand(p)
1390 if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then
1391 werror("bad mode or size in `"..p.."'")
1392 end
1393 if a.mode == "iJ" then
1394 wputlabel("IMM_", a.imm, 1)
1395 else
1396 wputszarg(sz, a.imm)
1397 end
1398 end
1399end
1400
1401map_op[".byte_*"] = op_data
1402map_op[".sbyte_*"] = op_data
1403map_op[".word_*"] = op_data
1404map_op[".dword_*"] = op_data
1405map_op[".aword_*"] = op_data
1406
1407------------------------------------------------------------------------------
1408
1409-- Pseudo-opcode to mark the position where the action list is to be emitted.
1410map_op[".actionlist_1"] = function(params)
1411 if not params then return "cvar" end
1412 local name = params[1] -- No syntax check. You get to keep the pieces.
1413 wline(function(out) writeactions(out, name) end)
1414end
1415
1416-- Pseudo-opcode to mark the position where the global enum is to be emitted.
1417map_op[".globals_1"] = function(params)
1418 if not params then return "prefix" end
1419 local prefix = params[1] -- No syntax check. You get to keep the pieces.
1420 wline(function(out) writeglobals(out, prefix) end)
1421end
1422
1423------------------------------------------------------------------------------
1424
1425-- Label pseudo-opcode (converted from trailing colon form).
1426map_op[".label_2"] = function(params)
1427 if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end
1428 local a = parseoperand(params[1])
1429 local mode, imm = a.mode, a.imm
1430 if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then
1431 -- Local label (1: ... 9:) or global label (->global:).
1432 waction("LABEL_LG", nil, 1)
1433 wputxb(imm)
1434 elseif mode == "iJ" then
1435 -- PC label (=>pcexpr:).
1436 waction("LABEL_PC", imm)
1437 else
1438 werror("bad label definition")
1439 end
1440 -- SETLABEL must immediately follow LABEL_LG/LABEL_PC.
1441 local addr = params[2]
1442 if addr then
1443 local a = parseoperand(params[2])
1444 if a.mode == "iPJ" then
1445 waction("SETLABEL", a.imm) -- !x64 (secpos)
1446 else
1447 werror("bad label assignment")
1448 end
1449 end
1450end
1451map_op[".label_1"] = map_op[".label_2"]
1452
1453------------------------------------------------------------------------------
1454
1455-- Alignment pseudo-opcode.
1456map_op[".align_1"] = function(params)
1457 if not params then return "numpow2" end
1458 local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]]
1459 if align then
1460 local x = align
1461 -- Must be a power of 2 in the range (2 ... 256).
1462 for i=1,8 do
1463 x = x / 2
1464 if x == 1 then
1465 waction("ALIGN", nil, 1)
1466 wputxb(align-1) -- Action byte is 2**n-1.
1467 return
1468 end
1469 end
1470 end
1471 werror("bad alignment")
1472end
1473
1474-- Spacing pseudo-opcode.
1475map_op[".space_2"] = function(params)
1476 if not params then return "num [, filler]" end
1477 waction("SPACE", params[1])
1478 local fill = params[2]
1479 if fill then
1480 fill = tonumber(fill)
1481 if not fill or fill < 0 or fill > 255 then werror("bad filler") end
1482 end
1483 wputxb(fill or 0)
1484end
1485map_op[".space_1"] = map_op[".space_2"]
1486
1487------------------------------------------------------------------------------
1488
1489-- Pseudo-opcode for (primitive) type definitions (map to C types).
1490map_op[".type_3"] = function(params, nparams)
1491 if not params then
1492 return nparams == 2 and "name, ctype" or "name, ctype, reg"
1493 end
1494 local name, ctype, reg = params[1], params[2], params[3]
1495 if not match(name, "^[%a_][%w_]*$") then
1496 werror("bad type name `"..name.."'")
1497 end
1498 local tp = map_type[name]
1499 if tp then
1500 werror("duplicate type `"..name.."'")
1501 end
1502 if reg and not map_reg_valid_base[reg] then
1503 werror("bad base register `"..(map_reg_rev[reg] or reg).."'")
1504 end
1505 -- Add #type to defines. A bit unclean to put it in map_archdef.
1506 map_archdef["#"..name] = "sizeof("..ctype..")"
1507 -- Add new type and emit shortcut define.
1508 local num = ctypenum + 1
1509 map_type[name] = {
1510 ctype = ctype,
1511 ctypefmt = format("Dt%X(%%s)", num),
1512 reg = reg,
1513 }
1514 wline(format("#define Dt%X(_V) (int)&(((%s *)0)_V)", num, ctype))
1515 ctypenum = num
1516end
1517map_op[".type_2"] = map_op[".type_3"]
1518
1519-- Dump type definitions.
1520local function dumptypes(out, lvl)
1521 local t = {}
1522 for name in pairs(map_type) do t[#t+1] = name end
1523 sort(t)
1524 out:write("Type definitions:\n")
1525 for _,name in ipairs(t) do
1526 local tp = map_type[name]
1527 local reg = tp.reg and map_reg_rev[tp.reg] or ""
1528 out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
1529 end
1530 out:write("\n")
1531end
1532
1533------------------------------------------------------------------------------
1534
1535-- Set the current section.
1536function _M.section(num)
1537 waction("SECTION")
1538 wputxb(num)
1539 wflush(true) -- SECTION is a terminal action.
1540end
1541
1542------------------------------------------------------------------------------
1543
1544-- Dump architecture description.
1545function _M.dumparch(out)
1546 out:write(format("DynASM %s version %s, released %s\n\n",
1547 _info.arch, _info.version, _info.release))
1548 dumpregs(out)
1549 dumpactions(out)
1550end
1551
1552-- Dump all user defined elements.
1553function _M.dumpdef(out, lvl)
1554 dumptypes(out, lvl)
1555 dumpglobals(out, lvl)
1556end
1557
1558------------------------------------------------------------------------------
1559
1560-- Pass callbacks from/to the DynASM core.
1561function _M.passcb(wl, we, wf, ww)
1562 wline, werror, wfatal, wwarn = wl, we, wf, ww
1563 return wflush
1564end
1565
1566-- Setup the arch-specific module.
1567function _M.setup(arch, opt)
1568 g_arch, g_opt = arch, opt
1569end
1570
1571-- Merge the core maps and the arch-specific maps.
1572function _M.mergemaps(map_coreop, map_def)
1573 setmetatable(map_op, { __index = map_coreop })
1574 setmetatable(map_def, { __index = map_archdef })
1575 return map_op, map_def
1576end
1577
1578return _M
1579
1580------------------------------------------------------------------------------
1581