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