#!/usr/local/bin/lua51 local bit = require("bit") local log = require("log") local amap = require("6map") local stdio = require("stdio") -- tcmod.lua - Toolchain Module local tcmod = { } tcmod.tokens = { } tcmod.todos = { duasm = { }, inasm = { }, solving = true, } local token_count = 1 local function gettokenkey(tk) for k, v in pairs(tcmod.tokens) do if tcmod.tokens[k] == tk.type then return k end end return nil end local function add_tokens(id, array) for i = 1, #array do if tcmod.tokens[array[i]] == nil then tcmod.tokens[array[i]] = token_count token_count = token_count + 1 end end tcmod.tokens[id] = array -- Check if it matches the type tcmod["is" .. id] = function(name) if type(name) == "table" then name = gettokenkey(name) end for i = 1, #array do if array[i] == name then return true end end return false end end tcmod.isnumber = function(n) if n:match("[0-9]") then return true end return false end add_tokens("mnemonic", { "mov", "cli", "hlt", "ret", "sti", "int", "call", "jmp", "dec", "jz", "jnz", "cmp", "inc", "xor", "jc", "jnc", "test", "or", "sti", "and", "cld", "rep_movsd", "cpuid", "rep_stosd", "add", "dec", "rdmsr", "wrmsr", "lgdt" }) add_tokens("arithmetic", { "+", "-", "*", "/", "^", "~", "|", "&" }) add_tokens("symbol", { ",", "[", "]", "(", ")", "{", "}", "!", "#", "?", ";", ":", "=" }) add_tokens("reg8", { "al", "ah", "bl", "bh", "cl", "ch", "dl", "dh" }) add_tokens("reg32", { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" }) add_tokens("creg", { "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7" }) add_tokens("reg64", { "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp" }) add_tokens("sreg", { "es", "ds", "cs", "ss" }) add_tokens("misc", { "asm", "integer", "string", "nwl", "id", "org" }) add_tokens("asmdu", { "du8", "du16", "du32", "du64" }) add_tokens("asmmem", { "u8", "u16", "u32", "u64" }) add_tokens("ctype", { "u8", "u16", "u32", "u64", "s8", "s16", "s32", "s64", "f32", "f64", "void" }) tcmod.isreg = function(name) if type(name) == "table" then name = gettokenkey(name) end return tcmod.isreg8(name) or tcmod.isreg32(name) or tcmod.isreg64(name) end tcmod.hexval = function(hex) local dig = hex:sub(3) local len = #dig local result = 0 for i = 1,len do local d = dig:sub(i, i) if d:lower() == "a" then d = 10 elseif d:lower() == "b" then d = 11 elseif d:lower() == "c" then d = 12 elseif d:lower() == "d" then d = 13 elseif d:lower() == "e" then d = 14 elseif d:lower() == "f" then d = 15 end result = result + d * (16 ^ (len - i)) end return result end tcmod.bitval = function(b) local dig = b:sub(3) local len = #dig local result = 0 for i = 1, len do local b = dig:sub(i, i) result = result + b * (2 ^ (len - i)) end return result end -- We solve using Reverse Polish Notation (RPN) local function solveexpr(info, expr) local resolve = false local postfix = { } local stack = { } local prec = { ["+"] = 0, ["-"] = 0, ["*"] = 1, ["/"] = 1, ["&"] = 2, ["|"] = 2, ["("] = 3, [")"] = 3, } local relIDmode = false for i = 1, #expr do local e = expr[i] if e.type == tcmod.tokens["&"] then if expr[i + 1] == nil or expr[i + 1].type == tcmod.tokens.id then relIDmode = true else local key = gettokenkey(e) if #stack == 0 then table.insert(stack, key) else local lkey = stack[#stack] if prec[lkey] < prec[key] then table.insert(stack, key) else if lkey ~= "(" then table.remove(stack, #stack) table.insert(stack, key) table.insert(postfix, lkey) else table.insert(stack, key) end end end end elseif e.type == tcmod.tokens["("] then local key = gettokenkey(e) table.insert(stack, key) elseif e.type == tcmod.tokens[")"] then local key = gettokenkey(e) while true do local p = table.remove(stack, #stack) if p == nil then log.error("missing open bracket for ')' at line " .. expr[1].line) end if p == "(" then break else table.insert(postfix, p) end end elseif tcmod.isarithmetic(e) then local key = gettokenkey(e) if #stack == 0 then table.insert(stack, key) else local lkey = stack[#stack] if prec[lkey] < prec[key] then table.insert(stack, key) else if lkey ~= "(" then table.remove(stack, #stack) table.insert(stack, key) table.insert(postfix, lkey) else table.insert(stack, key) end end end elseif e.type == tcmod.tokens.id then if info.symbols[e.raw] ~= nil then local val = info.symbols[e.raw] if relIDmode == true then val = val - info.offset -- Caller must do +data bytes size relIDmode = false end table.insert(postfix, val) else table.insert(postfix, 0) resolve = true if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. e.line) end end elseif e.type == tcmod.tokens.integer then table.insert(postfix, tonumber(e.raw)) else return nil end end for i = 1, #stack do if stack[#stack - i + 1] == "(" then log.error("missing closing bracket at line " .. expr[1].line) end table.insert(postfix, stack[#stack - i + 1]) end stack = { } -- SOLVING for i = 1, #postfix do local cur = postfix[i] if tonumber(cur) ~= nil then table.insert(stack, cur) else if #stack < 2 then log.error("more than 2 operands in stack for operator at line " .. expr[1].line) end local last = table.remove(stack, #stack) if cur == "+" then stack[#stack] = stack[#stack] + last elseif cur == "-" then stack[#stack] = stack[#stack] - last elseif cur == "*" then stack[#stack] = stack[#stack] * last elseif cur == "/" then stack[#stack] = stack[#stack] / last elseif cur == "&" then stack[#stack] = bit.band(stack[#stack], last) elseif cur == "|" then stack[#stack] = bit.bor(stack[#stack], last) end end end stack.resolve = resolve return stack end tcmod.fmtasmdu = function(info, stream) local dhdr = stream[1] local dtype = gettokenkey(stream[1]) local groups = { } local bytes = { } local resolve = false local cur = { } table.remove(stream, 1) for i = 1, #stream do local tk = stream[i] if tk.type == tcmod.tokens[","] then table.insert(groups, cur) cur = { } else table.insert(cur, tk) end end table.insert(groups, cur) -- Process groups for i = 1, #groups do local group = groups[i] local res = nil local tk = group[1] if tk.type ~= tcmod.tokens.string then res = solveexpr(info, group) end if res ~= nil and res.resolve == true and resolve == false then table.insert(stream, 1, dhdr) table.insert(tcmod.todos.duasm, { stream, info.offset }) resolve = true end if dtype == "du8" then if tk.type ~= tcmod.tokens.string and tk.type ~= tcmod.tokens.integer and tk.type ~= tcmod.tokens.id then log.error("only integers and string allowed for " .. dtype .. " line " .. tk.line) end if tk.type == tcmod.tokens.string then for i = 1, #tk.raw do local char = tk.raw:sub(i, i) table.insert(bytes, string.byte(char)) end else for i = 1, #group do if group[i].type == tcmod.tokens["&"] then res[1] = res[1] - 1 end end if res[1] < MAX_U8 then res[1] = res[1] + MAX_U8 end table.insert(bytes, res[1]) end elseif dtype == "du16" then if tk.type ~= tcmod.tokens.integer and tk.type ~= tcmod.tokens.id and tk.type ~= tcmod.tokens["&"] then log.error("only integers allowed for " .. dtype .. " line " .. tk.line) end for i = 1, #group do if group[i].type == tcmod.tokens["&"] then res[1] = res[1] - 2 end end if res[1] < 0 then res[1] = res[1] + MAX_U16 end local fmt = bit.nbytes(tonumber(res[1]), 2) for i = 1, #fmt do table.insert(bytes, fmt[i]) end elseif dtype == "du32" then if tk.type ~= tcmod.tokens.integer and tk.type ~= tcmod.tokens.id and tk.type ~= tcmod.tokens["&"] then log.error("only integers allowed for " .. dtype .. " line " .. tk.line) end for i = 1, #group do if group[i].type == tcmod.tokens["&"] then res[1] = res[1] - 4 end end if res[1] < 0 then res[1] = res[1] + MAX_U32 end local fmt = bit.nbytes(tonumber(res[1]), 4) for i = 1, #fmt do table.insert(bytes, fmt[i]) end elseif dtype == "du64" then if tk.type ~= tcmod.tokens.integer and tk.type ~= tcmod.tokens.id and tk.type ~= tcmod.tokens["&"] then log.error("only integers allowed for " .. dtype .. " line " .. tk.line) end for i = 1, #group do if group[i].type == tcmod.tokens["&"] then res[1] = res[1] - 8 end end if res[1] < 0 then res[1] = res[1] + MAX_U64 end local fmt = bit.nbytes(tonumber(res[1]), 8) for i = 1, #fmt do table.insert(bytes, fmt[i]) end end end return bytes end tcmod.readhdr = function(src) local hdr = src:read(12) if hdr == nil then return nil end local b = { string.byte((hdr), 1, 12) } local line = b[1] + bit.lshift(b[2], 8) + bit.lshift(b[3], 16) + bit.lshift(b[4], 24) local col = b[5] + bit.lshift(b[6], 8) + bit.lshift(b[7], 16) + bit.lshift(b[8], 24) local type = b[9] + bit.lshift(b[10], 8) local len = b[11] + bit.lshift(b[12], 8) local raw = nil if len > 0 then raw = src:read(len) end return { line = line, col = col, type = type, len = len, raw = raw } end tcmod.readasmline = function(src) local stream = { } while true do local hdr = tcmod.readhdr(src); if hdr == nil or hdr.type == tcmod.tokens.nwl or hdr.type == tcmod.tokens["}"] then if hdr.type == tcmod.tokens["}"] then src:seek("cur", -12) end break end if hdr.type == tcmod.tokens[";"] then while hdr ~= nil and hdr.type ~= tcmod.tokens.nwl do hdr = tcmod.readhdr(src) end return stream end table.insert(stream, hdr) end return stream end local function get_modrm_reg(mod) local regmap = { ["al"] = "000", ["ah"] = "100", ["bl"] = "011", ["bh"] = "111", ["cl"] = "001", ["ch"] = "101", ["dl"] = "010", ["dh"] = "110", ["ax"] = "000", ["si"] = "110", ["bx"] = "011", ["sp"] = "100", ["eax"] = "000", ["ecx"] = "001", ["edx"] = "010", ["ebx"] = "011", ["esi"] = "110", ["edi"] = "111", ["rax"] = "000", ["rcx"] = "001", ["rdx"] = "010", ["rbx"] = "011", ["rsp"] = "100", ["rdi"] = "111", ["rbp"] = "101", ["es"] = "000", ["cs"] = "001", ["ss"] = "010", ["ds"] = "011", } return regmap[mod] end local function get_modrm_rm(mod, reg) if mod == "00" then local map = { ["rdi"] = "111", } return map[reg] end return nil end -- It is base + index * scale + disp local function fmt_memory(info, expr) local result = { base = nil, index = nil, scale = nil, disp = nil, resolve = false } local stream = { } if expr[1].type == tcmod.tokens["["] then for i = 2, #expr - 1 do table.insert(stream, expr[i]) end elseif (gettokenkey(expr[1]) == "u8" or gettokenkey(expr[1]) == "u16" or gettokenkey(expr[1]) == "u32" or gettokenkey(expr[1]) == "u64") then for i = 3, #expr -1 do table.insert(stream, expr[i]) end else log.error("illegal token for memory at line " .. expr[1].line) end if #stream == 1 then if stream[1].type == tcmod.tokens.integer then result.disp = tonumber(stream[1].raw) elseif stream[1].type == tcmod.tokens.id then local val = info.symbols[stream[1].raw] if val == nil then result.resolve = true result.disp = 0 if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end else result.disp = tonumber(val) end elseif tcmod.isreg(stream[1]) then result.base = gettokenkey(stream[1]) end elseif #stream == 3 then if tcmod.isreg(stream[1]) and stream[2].type == tcmod.tokens["+"] and (stream[3].type == tcmod.tokens.integer or stream[3].type == tcmod.tokens.id) then result.base = stream[1].raw if stream[3].type == tcmod.tokens.integer then result.disp = tonumber(stream[3].raw) else local val = info.symbols[stream[3].raw] if val == nil then result.resolve = true result.disp = 0 if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end else result.disp = tonumber(val) end end elseif tcmod.isreg(stream[1]) and stream[2].type == tcmod.tokens["*"] and (stream[3].type == tcmod.tokens.integer or stream[3].type == tcmod.tokens.id) then result.index = stream[1].raw if stream[3].type == tcmod.tokens.integer then result.scale = tonumber(stream[3].raw) else local val = info.symbols[stream[3].raw] if val == nil then result.resolve = true result.scale = 0 if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end else result.scale = tonumber(val) end end else log.error("wrong memory format at line " .. expr[1].line) end elseif #stream == 5 then if tcmod.isreg(stream[1]) and stream[2].type == tcmod.tokens["+"] and tcmod.isreg(stream[3]) and stream[4].type == tcmod.tokens["+"] and (stream[5].type == tcmod.tokens.id or stream[5].type == tcmod.tokens.integer) then result.base = gettokenkey(stream[1]) result.index = gettokenkey(stream[3]) if stream[5].type == tcmod.tokens.integer then result.disp = tonumber(stream[5].raw) else local val = info.symbols[stream[5].raw] if val == nil then result.resolve = true result.disp = 0 if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end else result.disp = tonumber(val) end end else log.error("wrong memory format base + index + disp at line " .. expr[1].line) end elseif #stream == 7 then if tcmod.isreg(stream[1]) and stream[2].type == tcmod.tokens["+"] and tcmod.isreg(stream[3]) and stream[4].type == tcmod.tokens["*"] and (stream[5].type == tcmod.tokens.id or stream[5].type == tcmod.tokens.integer) and stream[6].type == tcmod.tokens["+"] and (stream[7].type == tcmod.tokens.id or stream[7].type == tcmod.tokens.integer) then result.base = gettokenkey(stream[1]) result.index = gettokenkey(stream[3]) if stream[5].type == tcmod.tokens.integer then result.scale = tonumber(stream[5].raw) else local val = info.symbols[stream[5].raw] if val == nil then result.resolve = true result.scale = 0 if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end else result.scale = tonumber(val) end end if stream[7].type == tcmod.tokens.integer then result.disp = tonumber(stream[7].raw) else local val = info.symbols[stream[7].raw] if val == nil then result.resolve = true result.disp = 0 if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end else result.disp = tonumber(val) end end else log.error("wrong memory format base + index * scale + disp at line " .. expr[1].line) end else log.error("wrong memory format base + index * scale + disp at line " .. expr[1].line) end return result end local function fmt1operand(info, match, groups) local ops = string.gmatch(match.opcode, "%S+") local bytes = { resolve = false } local mod = "11" local reg = "000" local rm = "000" local disp = nil local breg = nil local ireg = nil local disp = nil local imm = nil local rel = nil if match.operands[1] == ASM_REG8 or match.operands[1] == ASM_REG16 or match.operands[1] == ASM_REG32 or match.operands[1] == ASM_REG64 then local dstreg = gettokenkey(groups[1][1]) rm = get_modrm_reg(dstreg) elseif match.operands[1] == ASM_IMM8 then imm = tonumber(groups[1][1].raw) elseif match.operands[1] == ASM_REL32 then local name = groups[1][2].raw if info.symbols[name] == nil then bytes.resolve = true rel = 0 if tcmod.todos.solving == false then log.error("failed to find symbol `" .. name .. "` at line " .. groups[1][1].line) end else rel = info.symbols[name] end elseif match.operands[1] == ASM_MEM64 then if groups[1][1].type == tcmod.tokens["["] then if groups[1][2].type == tcmod.tokens.integer or groups[1][2].type == tcmod.tokens.id then mod = "00" local target = groups[1][2] rm = "101" if target.type == tcmod.tokens.integer then disp = bit.nbytes(tonumber(target.raw), 8) else local val = info.symbols[target.raw] if val ~= nil then disp = bit.nbytes(tonumber(val), 8) else bytes.resolve = true disp = bit.nbytes(0, 8) if tcmod.todos.solving == false then log.error("failed to find symbol at line " .. stream[1].line) end end end else log.error("wrong format for memory at line " .. group[1][1].line) end else log.error("memory must start with `[` first thanks. Line " .. groups[1][1].line) end end local cursz = 0 for tk in ops do if string.match(tk, "^0h(%x+)") ~= nil then table.insert(bytes, tcmod.hexval(tk)) cursz = cursz + 1 elseif tk == "/0" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) table.insert(bytes, modrm) cursz = cursz + 1 elseif tk == "/1" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) modrm = bit.bor(modrm, tcmod.bitval("0b001000")) table.insert(bytes, modrm) cursz = cursz + 1 elseif tk == "/2" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) modrm = bit.bor(modrm, tcmod.bitval("0b010000")) table.insert(bytes, modrm) cursz = cursz + 1 elseif tk == "/4" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) modrm = bit.bor(modrm, tcmod.bitval("0b100000")) table.insert(bytes, modrm) cursz = cursz + 1 elseif tk == "ib" then table.insert(bytes, imm) cursz = cursz + 1 elseif tk == "REX.W" then table.insert(bytes, tcmod.bitval("0b01001000")) cursz = cursz + 1 elseif tk == "cd" then local rel = rel - (info.offset + cursz + 4) if rel < 0 then rel = rel + MAX_U32 end local res = bit.nbytes(rel, 4) for i = 1, #res do table.insert(bytes, res[i]) end end end if disp ~= nil then for i = 1, #disp do table.insert(bytes, disp[i]) end end return bytes end local function fmt2operands(info, match, groups) local ops = string.gmatch(match.opcode, "%S+") local bytes = { resolve = false } local mod = "11" local reg = "000" local rm = "000" local memfmt = nil if (match.operands[1] == ASM_REG8 and match.operands[2] == ASM_REG8) or (match.operands[1] == ASM_REG32 and match.operands[2] == ASM_REG32) or (match.operands[1] == ASM_REG64 and match.operands[2] == ASM_REG64) then local dstreg = gettokenkey(groups[1][1]) local srcreg = gettokenkey(groups[2][1]) local mod = "11" reg = get_modrm_reg(srcreg) rm = get_modrm_reg(dstreg) elseif (match.operands[1] == ASM_REG8 and match.operands[2] == ASM_IMM8) or (match.operands[1] == ASM_REG32 and match.operands[2] == ASM_IMM32) or (match.operands[1] == ASM_REG64 and match.operands[2] == ASM_IMM64) then local dstreg = gettokenkey(groups[1][1]) local mod = "00" reg = get_modrm_reg(dstreg) rm = get_modrm_reg(dstreg) local stack = solveexpr(info, groups[2]) imm = stack[1] bytes.resolve = stack.resolve for i = 1, #groups[2] do if groups[2][i].type == tcmod.tokens["&"] then if match.operands[1] == ASM_REG8 then imm = imm - 1 elseif match.operands[1] == ASM_REG32 then imm = imm - 4 elseif match.operands[1] == ASM_REG64 then imm = imm - 8 end end end elseif match.operands[1] == ASM_MEM16 and match.operands[2] == ASM_IMM16 or match.operands[1] == ASM_MEM32 and match.operands[2] == ASM_IMM32 or match.operands[1] == ASM_MEM64 and match.operands[2] == ASM_IMM32 then memfmt = fmt_memory(info, groups[1]) if memfmt.base ~= nil and memfmt.disp == nil then mod = "00" rm = get_modrm_rm(mod, memfmt.base) else log.error("for now only [base] allowed. Line " .. groups[1][1].line) end imm = tonumber(groups[2][1].raw) else log.error("cannot process current instruction for now line " .. groups[1][1].line) end local addon = false local canaddon = false for tk in ops do local cval = nil if string.match(tk, "^0h(%x+)") ~= nil then cval = tcmod.hexval(tk) elseif tk == "/r" then modrm = tcmod.bitval("0b" .. mod .. reg .. rm) cval = modrm elseif tk == "/0" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) cval = modrm elseif tk == "/1" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) modrm = bit.bor(modrm, tcmod.bitval("0b001000")) cval = modrm elseif tk == "/7" then modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.bor(modrm, tcmod.bitval("0b111000")) cval = modrm elseif tk == "/4" then local modrm = tcmod.bitval("0b" .. mod .. reg .. rm) modrm = bit.band(modrm, tcmod.bitval("0b11000111")) modrm = bit.bor(modrm, tcmod.bitval("0b100000")) cval = modrm elseif tk == "+" then if canaddon == false then addon = true else canaddon = false end elseif tk == "rb" or tk == "rw" or tk == "rd" then cval = tcmod.bitval("0b" .. reg) elseif tk == "ib" then cval = imm elseif tk == "iw" then local res = bit.nbytes(imm, 2) for i = 1, #res do table.insert(bytes, res[i]) end elseif tk == "id" then local res = bit.nbytes(imm, 4) for i = 1, #res do table.insert(bytes, res[i]) end elseif tk == "io" then local res = bit.nbytes(imm, 8) for i = 1, #res do table.insert(bytes, res[i]) end elseif tk == "REX.W" then cval = tcmod.bitval("0b01001000") canaddon = true end if cval ~= nil then if addon == true then bytes[#bytes] = bytes[#bytes] + cval addon = false else table.insert(bytes, cval) end end end return bytes end tcmod.fmtasminst = function(info, stream) local mnemonic = stream[1] local groups = { } -- Operands local bytes = { } table.remove(stream, 1) if tcmod.ismnemonic(mnemonic) == false then log.error("unknown mnemonic at line " .. mnemonic.line) end ------------------------------------------------------------------------- -- GROUPS BY COMMAS ------------------------------------------------------------------------- local cur = { } for i = 1, #stream do local tk = stream[i] if tk.type == tcmod.tokens[","] then table.insert(groups, cur) cur = { } else table.insert(cur, tk) end end if #cur > 0 then table.insert(groups, cur) end if #groups > 2 then log.error("more operands than 2 at line " .. mnemonic.line) end ------------------------------------------------------------------------- -- FORMAT ------------------------------------------------------------------------- local fmt = { mnemonic = nil, operands = { } } if #groups == 0 then fmt.mnemonic = gettokenkey(mnemonic) elseif #groups == 1 then fmt.mnemonic = gettokenkey(mnemonic) if tcmod.isreg8(groups[1][1]) then fmt.operands[1] = ASM_REG8 elseif tcmod.isreg32(groups[1][1]) then fmt.operands[1] = ASM_REG32 elseif tcmod.isreg64(groups[1][1]) then fmt.operands[1] = ASM_REG64 elseif groups[1][1].type == tcmod.tokens.integer then local val = tonumber(groups[1][1].raw) if val < 255 then fmt.operands[1] = ASM_IMM8 end elseif groups[1][1].type == tcmod.tokens["&"] then fmt.operands[1] = ASM_REL32 elseif groups[1][1].type == tcmod.tokens["["] then fmt.operands[1] = ASM_MEM64 end elseif #groups == 2 then fmt.mnemonic = gettokenkey(mnemonic) if tcmod.isreg8(groups[1][1]) then fmt.operands[1] = ASM_REG8 end if tcmod.isreg8(groups[2][1]) then fmt.operands[2] = ASM_REG8 end if tcmod.isreg32(groups[1][1]) then fmt.operands[1] = ASM_REG32 end if tcmod.isreg32(groups[2][1]) then fmt.operands[2] = ASM_REG32 end if tcmod.isreg64(groups[1][1]) then fmt.operands[1] = ASM_REG64 end if tcmod.isreg64(groups[2][1]) then fmt.operands[2] = ASM_REG64 end -- IMM if tcmod.isreg8(groups[1][1]) and (groups[2][1].type == tcmod.tokens.integer or groups[2][1].type == tcmod.tokens.id) then fmt.operands[2] = ASM_IMM8 end if tcmod.isreg32(groups[1][1]) and (groups[2][1].type == tcmod.tokens.integer or groups[2][1].type == tcmod.tokens.id) then fmt.operands[2] = ASM_IMM32 end if tcmod.isreg64(groups[1][1]) and (groups[2][1].type == tcmod.tokens.integer or groups[2][1].type == tcmod.tokens.id) then fmt.operands[2] = ASM_IMM64 end if groups[1][1].type == tcmod.tokens["["] and (groups[2][1].type == tcmod.tokens.id or groups[2][1].type == tcmod.tokens.integer) then fmt.operands[1] = ASM_MEM64 fmt.operands[2] = ASM_IMM32 end if gettokenkey(groups[1][1]) == "u32" and (groups[2][1].type == tcmod.tokens.id or groups[2][1].type == tcmod.tokens.integer) then fmt.operands[1] = ASM_MEM32 fmt.operands[2] = ASM_IMM32 end if gettokenkey(groups[1][1]) == "u16" and (groups[2][1].type == tcmod.tokens.id or groups[2][1].type == tcmod.tokens.integer) then fmt.operands[1] = ASM_MEM16 fmt.operands[2] = ASM_IMM16 end end local match = amap.matches(fmt) if match == nil then log.error("failed to match instruction at line " .. mnemonic.line) end ------------------------------------------------------------------------- -- ADDING BYTES ------------------------------------------------------------------------- local ops = string.gmatch(match.opcode, "%S+") if #match.operands == 0 then for tk in ops do if string.match(tk, "^0h(%x+)") ~= nil then table.insert(bytes, tcmod.hexval(tk)) end end elseif #match.operands == 1 then local res = fmt1operand(info, match, groups) for i = 1, #res do table.insert(bytes, res[i]) end if res.resolve == true then table.insert(stream, 1, mnemonic) table.insert(tcmod.todos.inasm, { stream, info.offset }) end elseif #match.operands == 2 then local res = fmt2operands(info, match, groups) for i = 1, #res do table.insert(bytes, res[i]) end if res.resolve == true then table.insert(stream, 1, mnemonic) table.insert(tcmod.todos.inasm, { stream, info.offset }) end end return bytes end tcmod.resolve = function(info, dst) tcmod.todos.solving = false for i = 1, #tcmod.todos.duasm do local entry = tcmod.todos.duasm[i] local bytes = { } local stream = entry[1] local offset = entry[2] info.offset = offset local bytes = tcmod.fmtasmdu(info, stream) dst:seek("set", offset - info.org) for j = 1, #bytes do stdio.writeu8(dst, bytes[j]) end end for i = 1, #tcmod.todos.inasm do local entry = tcmod.todos.inasm[i] local bytes = { } local stream = entry[1] local offset = entry[2] info.offset = offset local bytes = tcmod.fmtasminst(info, stream) dst:seek("set", offset - info.org) for j = 1, #bytes do stdio.writeu8(dst, bytes[j]) end end end return tcmod