📄 dasm_x86.lua
字号:
-------------------------------------------------------------------------------- DynASM x86 module.---- Copyright (C) 2005-2008 Mike Pall. All rights reserved.-- See dynasm.lua for full copyright notice.-------------------------------------------------------------------------------- Module information:local _info = { arch = "x86", description = "DynASM x86 (i386) module", version = "1.1.4", vernum = 10104, release = "2008-01-29", author = "Mike Pall", license = "MIT",}-- Exported glue functions for the arch-specific module.local _M = { _info = _info }-- Cache library functions.local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairslocal assert, unpack = assert, unpacklocal _s = stringlocal sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.charlocal find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsublocal concat, sort = table.concat, table.sortlocal char, unpack = string.char, unpack-- Inherited tables and callbacks.local g_opt, g_archlocal wline, werror, wfatal, wwarn-- Action name list.-- CHECK: Keep this in sync with the C code!local action_names = { -- int arg, 1 buffer pos: "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB", -- action arg (1 byte), int arg, 1 buffer pos (num): "SPACE", -- ptrdiff_t arg, 1 buffer pos (address): !x64 "SETLABEL", "REL_A", -- action arg (1 byte) or int arg, 2 buffer pos (link, offset): "REL_LG", "REL_PC", -- action arg (1 byte) or int arg, 1 buffer pos (link): "IMM_LG", "IMM_PC", -- action arg (1 byte) or int arg, 1 buffer pos (offset): "LABEL_LG", "LABEL_PC", -- action arg (1 byte), 1 buffer pos (offset): "ALIGN", -- action arg (1 byte), no buffer pos. "ESC", -- no action arg, no buffer pos. "MARK", -- action arg (1 byte), no buffer pos, terminal action: "SECTION", -- no args, no buffer pos, terminal action: "STOP"}-- Maximum number of section buffer positions for dasm_put().-- CHECK: Keep this in sync with the C code!local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.-- Action name -> action number (dynamically generated below).local map_action = {}-- First action number. Everything below does not need to be escaped.local actfirst = 256-#action_names-- Action list buffer and string (only used to remove dupes).local actlist = {}local actstr = ""-- Argument list for next dasm_put(). Start with offset 0 into action list.local actargs = { 0 }-- Current number of section buffer positions for dasm_put().local secpos = 1-------------------------------------------------------------------------------- Compute action numbers for action names.for n,name in ipairs(action_names) do local num = actfirst + n - 1 map_action[name] = numend-- Dump action names and numbers.local function dumpactions(out) out:write("DynASM encoding engine action codes:\n") for n,name in ipairs(action_names) do local num = map_action[name] out:write(format(" %-10s %02X %d\n", name, num, num)) end out:write("\n")end-- Write action list buffer as a huge static C array.local function writeactions(out, name) local nn = #actlist local last = actlist[nn] or 255 actlist[nn] = nil -- Remove last byte. if nn == 0 then nn = 1 end out:write("static const unsigned char ", name, "[", nn, "] = {\n") local s = " " for n,b in ipairs(actlist) do s = s..b.."," if #s >= 75 then assert(out:write(s, "\n")) s = " " end end out:write(s, last, "\n};\n\n") -- Add last byte back.end-------------------------------------------------------------------------------- Add byte to action list.local function wputxb(n) assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range") actlist[#actlist+1] = nend-- Add action to list with optional arg. Advance buffer pos, too.local function waction(action, a, num) wputxb(assert(map_action[action], "bad action name `"..action.."'")) if a then actargs[#actargs+1] = a end if a or num then secpos = secpos + (num or 1) endend-- Add call to embedded DynASM C code.local function wcall(func, args) wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)end-- Delete duplicate action list chunks. A tad slow, but so what.local function dedupechunk(offset) local al, as = actlist, actstr local chunk = char(unpack(al, offset+1, #al)) local orig = find(as, chunk, 1, true) if orig then actargs[1] = orig-1 -- Replace with original offset. for i=offset+1,#al do al[i] = nil end -- Kill dupe. else actstr = as..chunk endend-- Flush action list (intervening C code or buffer pos overflow).local function wflush(term) local offset = actargs[1] if #actlist == offset then return end -- Nothing to flush. if not term then waction("STOP") end -- Terminate action list. dedupechunk(offset) wcall("put", actargs) -- Add call to dasm_put(). actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). secpos = 1 -- The actionlist offset occupies a buffer position, too.end-- Put escaped byte.local function wputb(n) if n >= actfirst then waction("ESC") end -- Need to escape byte. wputxb(n)end-------------------------------------------------------------------------------- Global label name -> global label number. With auto assignment on 1st use.local next_global = 10local map_global = setmetatable({}, { __index = function(t, name) if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end local n = next_global if n > 246 then werror("too many global labels") end next_global = n + 1 t[name] = n return nend})-- Dump global labels.local function dumpglobals(out, lvl) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("Global labels:\n") for i=10,next_global-1 do out:write(format(" %s\n", t[i])) end out:write("\n")end-- Write global label enum.local function writeglobals(out, prefix) local t = {} for name, n in pairs(map_global) do t[n] = name end out:write("enum {\n") for i=10,next_global-1 do out:write(" ", prefix, t[i], ",\n") end out:write(" ", prefix, "_MAX\n};\n")end-------------------------------------------------------------------------------- Arch-specific maps.local map_archdef = {} -- Ext. register name -> int. name.local map_reg_rev = {} -- Int. register name -> ext. name.local map_reg_num = {} -- Int. register name -> register number.local map_reg_opsize = {} -- Int. register name -> operand size.local map_reg_valid_base = {} -- Int. register name -> valid base register?local map_reg_valid_index = {} -- Int. register name -> valid index register?local reg_list = {} -- Canonical list of int. register names.local map_type = {} -- Type name -> { ctype, reg }local ctypenum = 0 -- Type number (for _PTx macros).local addrsize = "d" -- Size for address operands. !x64-- Helper function to fill register maps.local function mkrmap(sz, names) for n,name in ipairs(names) do local iname = format("@%s%x", sz, n-1) reg_list[#reg_list+1] = iname map_archdef[name] = iname map_reg_rev[iname] = name map_reg_num[iname] = n-1 map_reg_opsize[iname] = sz if sz == addrsize then map_reg_valid_base[iname] = true map_reg_valid_index[iname] = true end end reg_list[#reg_list+1] = ""end-- Integer registers (dword, word and byte sized).mkrmap("d", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})map_reg_valid_index[map_archdef.esp] = nilmkrmap("w", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})mkrmap("b", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})-- FP registers (internally tword sized, but use "f" as operand size).mkrmap("f", {"st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"})-- SSE registers (oword sized, but qword and dword accessible).mkrmap("o", {"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"})-- Operand size prefixes to codes.local map_opsize = { byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t", aword = addrsize,}-- Operand size code to number.local map_opsizenum = { b = 1, w = 2, d = 4, q = 8, o = 16, t = 10,}-- Operand size code to name.local map_opsizename = { b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword", f = "fpword",}-- Valid index register scale factors.local map_xsc = { ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,}-- Condition codes.local map_cc = { o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7, s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15, c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7, nge = 12, ge = 13, ng = 14, g = 15,}-- Reverse defines for registers.function _M.revdef(s) return gsub(s, "@%w+", map_reg_rev)end-- Dump register names and numberslocal function dumpregs(out) out:write("Register names, sizes and internal numbers:\n") for _,reg in ipairs(reg_list) do if reg == "" then out:write("\n") else local name = map_reg_rev[reg] local num = map_reg_num[reg] local opsize = map_opsizename[map_reg_opsize[reg]] out:write(format(" %-5s %-8s %d\n", name, opsize, num)) end endend-------------------------------------------------------------------------------- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).local function wputlabel(aprefix, imm, num) if type(imm) == "number" then waction(aprefix.."LG", nil, num); wputxb(imm) else waction(aprefix.."PC", imm, num) endend-- Put signed byte or arg.local function wputsbarg(n) if type(n) == "number" then if n < -128 or n > 127 then werror("signed immediate byte out of range") end if n < 0 then n = n + 256 end wputb(n) else waction("IMM_S", n) endend-- Put unsigned byte or arg.local function wputbarg(n) if type(n) == "number" then if n < 0 or n > 255 then werror("unsigned immediate byte out of range") end wputb(n) else waction("IMM_B", n) endend-- Put unsigned word or arg.local function wputwarg(n) if type(n) == "number" then if n < 0 or n > 65535 then werror("unsigned immediate word out of range") end local r = n%256; n = (n-r)/256; wputb(r); wputb(n); else waction("IMM_W", n) endend-- Put signed or unsigned dword or arg.local function wputdarg(n) local tn = type(n) if tn == "number" then if n < 0 then n = n + 4294967296 end local r = n%256; n = (n-r)/256; wputb(r); r = n%256; n = (n-r)/256; wputb(r); r = n%256; n = (n-r)/256; wputb(r); wputb(n); elseif tn == "table" then wputlabel("IMM_", n[1], 1) else waction("IMM_D", n) endend-- Put operand-size dependent number or arg (defaults to dword).local function wputszarg(sz, n) if not sz or sz == "d" then wputdarg(n) elseif sz == "w" then wputwarg(n) elseif sz == "b" then wputbarg(n) elseif sz == "s" then wputsbarg(n) else werror("bad operand size") endend-- Put multi-byte opcode with operand-size dependent modifications.local function wputop(sz, op) local r if sz == "w" then wputb(102) end if op >= 16777216 then r = op % 16777216 wputb((op-r) / 16777216) op = r end if op >= 65536 then r = op % 65536 wputb((op-r) / 65536) op = r end if op >= 256 then r = op % 256 wputb((op-r) / 256) op = r end if sz == "b" then op = op - 1 end wputb(op)end-- Put ModRM or SIB formatted byte.local function wputmodrm(m, s, rm) assert(m < 4 and s < 8 and rm < 8, "bad modrm operands") wputb(64*m + 8*s + rm)end-- Put ModRM/SIB plus optional displacement.local function wputmrmsib(t, s, imark) -- Register mode. if sub(t.mode, 1, 1) == "r" then wputmodrm(3, s, t.reg) return end local disp = t.disp local tdisp = type(disp) -- No base register? if not t.reg then if t.xreg then -- Indexed mode with index register only. wputmodrm(0, s, 4) -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -