From 5d2eafb8790d7a1030aca0dbb75201073aacd1d9 Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Sun, 4 Aug 2013 10:41:28 -0300 Subject: [PATCH] Uploading Lua Assembler/Disassembler for Lua 5.2 --- 5.2/ChangeLog | 6 + 5.2/README | 5 + 5.2/ToDo | 22 ++ 5.2/assembler.lua | 685 ++++++++++++++++++++++++++++++++++ 5.2/disassembler.lua | 754 +++++++++++++++++++++++++++++++++++++ 5.2/doc/fat_rec.asm | 23 ++ 5.2/doc/hello.asm | 6 + 5.2/doc/hello.lua | 1 + 5.2/doc/logo1.png | Bin 0 -> 11125 bytes 5.2/doc/manual.html | 869 +++++++++++++++++++++++++++++++++++++++++++ 5.2/ladconf.lua | 230 ++++++++++++ 5.2/luaa.lua | 72 ++++ 5.2/luad.lua | 62 +++ 13 files changed, 2735 insertions(+) create mode 100644 5.2/ChangeLog create mode 100644 5.2/README create mode 100644 5.2/ToDo create mode 100644 5.2/assembler.lua create mode 100644 5.2/disassembler.lua create mode 100644 5.2/doc/fat_rec.asm create mode 100644 5.2/doc/hello.asm create mode 100644 5.2/doc/hello.lua create mode 100644 5.2/doc/logo1.png create mode 100644 5.2/doc/manual.html create mode 100644 5.2/ladconf.lua create mode 100755 5.2/luaa.lua create mode 100755 5.2/luad.lua diff --git a/5.2/ChangeLog b/5.2/ChangeLog new file mode 100644 index 0000000..577c7f5 --- /dev/null +++ b/5.2/ChangeLog @@ -0,0 +1,6 @@ +Version 0.2 - 28/03/2012 +* Ported code from Lua 5.1.4 to Lua 5.2.0 ++ Support to Lua 5.2.0 +- Support to Lua 5.1.4 +Version 0.1 - 19/07/2011 +* Initial version for Lua 5.1.4 diff --git a/5.2/README b/5.2/README new file mode 100644 index 0000000..5f0add8 --- /dev/null +++ b/5.2/README @@ -0,0 +1,5 @@ +Lua Assembler/Disassembler 0.2, relased on March 28 2012. + +For further information about Lua Assembler/Disassembler, +as well as installion instructions and license details, +please, see doc/manual.html. diff --git a/5.2/ToDo b/5.2/ToDo new file mode 100644 index 0000000..9543e01 --- /dev/null +++ b/5.2/ToDo @@ -0,0 +1,22 @@ + +Assembler + +- Fix RK to work with constants larger than 2^8. +- Add following command line options: + - endianness; + - size of string constants; + - size of ints; + - type of lua numbers. +- Insert line counter to improve error messages. +- Add operator '...' to allow the definition of vararg functions. +- Add following instructions: JNE, JG, JL, JGE, JLE and JE. +- Add below constants/parameters if necessary: + - TRUE; + - FALSE; + - NIL. + +Disassembler + +- Make it work with big endian code. +- Write '(...)' instead of '(0)' when a function is vararg. + diff --git a/5.2/assembler.lua b/5.2/assembler.lua new file mode 100644 index 0000000..14232ea --- /dev/null +++ b/5.2/assembler.lua @@ -0,0 +1,685 @@ +local re = require("re") +local ladconf = require("ladconf") + +local OPCODE = { MOVE = 0, LOADK = 1, LOADKX = 2, LOADBOOL = 3, LOADNIL = 4, + GETUPVAL = 5, GETTABUP = 6, GETTABLE = 7, SETTABUP = 8, + SETUPVAL = 9, SETTABLE = 10, NEWTABLE = 11, SELF = 12, + ADD = 13, SUB = 14, MUL = 15, DIV = 16, MOD = 17, POW = 18, + UNM = 19, NOT = 20, LEN = 21, CONCAT = 22, JMP = 23, + EQ = 24, LT = 25, LE = 26, TEST = 27, TESTSET = 28, + CALL = 29, TAILCALL = 30, RETURN = 31, FORLOOP = 32, + FORPREP = 33, TFORCALL = 34, TFORLOOP = 35, SETLIST = 36, + CLOSURE = 37, VARARG = 38, EXTRAARG = 39 } + +local grammar = [[ + prog <- s ( {:tag: '' -> 'prog':} function )* -> {} !. + function <- ( {:tag: '' -> 'func':} {:header: header:} {:codelist: codelist:}) -> {} + header <- ("function" s {:name: name:} s "(" s {:numparams: n:} s ")" s ":" s) -> {} + codelist <- code+ -> {} + code <- autocode / manualcode + autocode <- ( {:tag: '' -> 'code':} n s ln s op s param s ("," s param s)* ) -> {} + manualcode <- ( {:tag: '' -> 'code':} ({:label: label:} s )? op s param s ("," s param s)* ) -> {} + n <- %d+ + label <- name ":" + name <- ( !reserved {[a-zA-Z_][a-zA-Z0-9_]*} ) + ln <- "[" %d+ "]" + op <- {:op: !reserved %a+ -> to_upper:} + param <- register / number / string + register <- ( {:tag: '' -> 'reg':} ("$" {n}) -> to_number ) -> {} + number <- ( {:tag: '' -> 'num':} ( hex / float / int ) ) -> {} + string <- ( {:tag: '' -> 'str':} ( name / shortstr ) ) -> {} + shortstr <- ( '"' {('\\' / '\"' / !'"' .)*} '"' / "'" {("\\" / "\'" / !"'" .)*} "'" ) -> to_string + hex <- ( {:tag: '' -> 'int':} {"-"? "0" [xX] %x+} -> to_number ) -> {} + float <- ( {:tag: '' -> 'float':} {"-"? ( (%d+ "." %d* / "." %d+) e? / %d+ e )} -> to_number ) -> {} + e <- [eE] [+-]? n + int <- ( {:tag: '' -> 'int':} {"-"? n} -> to_number ) -> {} + s <- (space / comment)* + space <- %s+ + comment <- ";" (!%nl .)* + reserved <- "function" +]] + +local function fixed_string(s) + s = string.gsub(s, "\\\"", '\"') + s = string.gsub(s, "\\\\", '\\') + s = string.gsub(s, "\\a", '\a') + s = string.gsub(s, "\\b", '\b') + s = string.gsub(s, "\\f", '\f') + s = string.gsub(s, "\\n", '\n') + s = string.gsub(s, "\\r", '\r') + s = string.gsub(s, "\\t", '\t') + s = string.gsub(s, "\\v", '\v') + s = string.gsub(s, "\\(%d+)", function (s) return string.char (tonumber(s)) end ) + return s +end + +local defs = { + to_number = function (n) return tonumber(n) end, + to_string = function (s) return fixed_string(s) end, + to_upper = function (s) return string.upper(s) end, +} + +local parser = re.compile(grammar, defs) + +local function parse(contents) + return parser:match(contents) +end + +local function print_header(t) + io.write(string.format("\nfunction %s(%s):\n", t.name, t.numparams)) +end + +local function print_param(t) + if t.tag == 'reg' then + io.write(string.format("$%d", t[1])) + elseif t.tag == 'num' then + io.write(string.format("%s", tostring(t[1]))) + elseif t.tag == 'str' then + io.write(string.format("%s", t[1])) + end +end + +local function print_sep() + io.write(string.format(", ")) +end + +local function print_code(t, i) + if t.tag == 'code' then + if t.label then io.write(string.format("%s:", t.label)) end + io.write(string.format("\t%d", i)) + io.write(string.format("\t%-9s\t", t.op)) + for i=1,#t-1 do + print_param(t[i]) + print_sep() + end + print_param(t[#t]) + io.write(string.format("\n")) + end +end + +local function print_codelist(t) + for i=1,#t do + print_code(t[i], i) + end +end + +local function print_func(t) + if t.tag == 'func' then + print_header(t.header) + print_codelist(t.codelist) + end +end + +local function print_ast(t) + if t.tag == 'prog' then + for k,v in ipairs(t) do + print_func(v) + end + end +end + +local function converge(ast) + if ast.tag ~= 'prog' then return nil end + local t = {} + for k,v in ipairs(ast) do + if v.tag ~= 'func' then return nil end + local name = v.header.name + t[name] = {} + t[name].id = k + end + return t +end + +local function R(t, f) + if t.tag ~= 'reg' then error("Register expected") end + local r = t[1] + if not f.register[r] then + f.register[r] = r + f.maxstacksize = f.maxstacksize + 1 + end + return r +end + +local function Int(t) + if t.tag ~= 'num' or t[1].tag ~= 'int' then + error("Integer expected") + end + local i = t[1][1] + if i < 0 then error("Positive integer expected") end + return i +end + +local function Label(t, f) + local l = t[1] + if not f.label[l] then error(string.format("Label %s not defined", l)) end + return f.label[l] +end + +local function Kst(t, f) + local k, k_type + + if t.tag == 'num' then + k = t[1][1] + k_type = ladconf.LUA_TNUMBER + elseif t.tag == 'str' then + k = t[1] + k_type = ladconf.LUA_TSTRING + else + error ("Constant not implemented") + end + + if not f.const[k] then + local n = f.sizek + 1 + f.sizek = n + f.const[k] = n + f.k[n] = {} + f.k[n].k_type = k_type + f.k[n].value = k + end + + return f.const[k] +end + +local function KPROTO(t, f, a) + if t.tag ~= 'str' then error("Function name expected") end + + local name = t[1] + + if not a[name] then + error(string.format("Function %s not defined", name)) + end + + if not f.func[name] then + local n = f.sizep + 1 + f.sizep = n + f.func[name] = n + f.p[n] = {} + f.p[n] = name + end + + return f.func[name] +end + +local function UpValue(t, f) + if t.tag ~= 'str' then error("String/Name expected") end + + local name = t[1] + + if not f.upval[name] then + local n = f.sizeupvalues + 1 + f.sizeupvalues = n + f.upval[name] = n + f.upvalues[n] = {} + if name == "_ENV" then + f.upvalues[n].instack = 0 + else + f.upvalues[n].instack = 1 + end + f.upvalues[n].idx = 0 + f.upvalues[n].name = name + end + + return f.upval[name] +end + +local function RK(t, f) + if t.tag == 'reg' then + return R(t, f) + end + -- TODO: fix it (does not work if sizek > 2^8) + local k = Kst(t, f) + if k < ladconf.MAXINDEXRK then + return k + ladconf.MAXINDEXRK + end + return k +end + +local function SBX(t, f, n) + if t.tag == 'num' then + return Int(t) - n + elseif t.tag == 'str' then + return Label(t, f) - n + end +end + +local function sew_label(i, t, n) + if i.label then + local l = i.label + if not t[l] then t[l] = n + else error (string.format("Label %s already defined\n", l)) + end + end +end + +local function sew_code(t, ast, all) + local codelist = ast[t.id].codelist + t.sizecode = #codelist + -- first check for labels + t.label = {} + for k,v in ipairs(codelist) do + sew_label(v, t.label, k) + end + -- after that check code + t.code = {} + for k,v in ipairs(codelist) do + if v.tag ~= 'code' then return nil end + local f,i = t,{} + local op = v.op + t.code[k] = i + i.O = OPCODE[op] + if op == "MOVE" or + op == "UNM" or + op == "NOT" or + op == "LEN" then + -- R(A) R(B) + i.A = R(v[1], f) + i.B = R(v[2], f) + i.C = 0 + elseif op == "LOADK" then + -- R(A) Kst(Bx) + i.A = R(v[1], f) + i.Bx = Kst(v[2], f) + elseif op == "LOADKX" then + -- R(A) + if codelist[k+1].op ~= "EXTRAARG" then + error("For LOADKX next instruction is always EXTRAARG") + end + i.A = R(v[1], f) + i.Bx = 0 + elseif op == "LOADBOOL" or + op == "NEWTABLE" or + op == "CALL" or + op == "TAILCALL" or + op == "SETLIST" then + -- R(A) B C + i.A = R(v[1], f) + i.B = Int(v[2]) + i.C = Int(v[3]) + elseif op == "LOADNIL" or + op == "RETURN" then + -- R(A) B + i.A = R(v[1], f) + i.B = Int(v[2]) + i.C = 0 + elseif op == "GETUPVAL" or + op == "SETUPVAL" then + -- R(A) UpValue(B) + i.A = R(v[1], f) + i.B = UpValue(v[2], f) - 1 + i.C = 0 + elseif op == "GETTABUP" then + -- R(A) UpValue(B) RK(C) + i.A = R(v[1], f) + i.B = UpValue(v[2], f) - 1 + i.C = RK(v[3], f) + elseif op == "GETTABLE" or + op == "SELF" then + -- R(A) R(B) RK(C) + i.A = R(v[1], f) + i.B = R(v[2], f) + i.C = RK(v[3], f) + elseif op == "SETTABUP" then + -- UpValue(A) RK(B) RK(C) + i.A = UpValue(v[1], f) - 1 + i.B = RK(v[2], f) + i.C = RK(v[3], f) + elseif op == "SETTABLE" or + op == "ADD" or + op == "SUB" or + op == "MUL" or + op == "DIV" or + op == "MOD" or + op == "POW" then + -- R(A) RK(B) RK(C) + i.A = R(v[1], f) + i.B = RK(v[2], f) + i.C = RK(v[3], f) + elseif op == "CONCAT" then + -- R(A) R(B) R(C) + i.A = R(v[1], f) + i.B = R(v[2], f) + i.C = R(v[3], f) + elseif op == "JMP" then + -- A sBx + i.A = Int(v[1]) + i.sBx = SBX(v[2], f, k) + elseif op == "EQ" or + op == "LT" or + op == "LE" then + -- A RK(B) RK(C) + i.A = Int(v[1]) + i.B = RK(v[2], f) + i.C = RK(v[3], f) + elseif op == "TEST" or + op == "TFORCALL" then + -- R(A) C + i.A = R(v[1], f) + i.B = 0 + i.C = Int(v[2]) + elseif op == "TESTSET" then + -- R(A) R(B) C + i.A = R(v[1], f) + i.B = R(v[2], f) + i.C = Int(v[3]) + elseif op == "FORLOOP" or + op == "FORPREP" or + op == "TFORLOOP" then + -- R(A) sBx + i.A = R(v[1], f) + i.sBx = SBX(v[2], f, k) + elseif op == "CLOSURE" then + -- R(A) KPROTO(Bx) + i.A = R(v[1], f) + i.Bx = KPROTO(v[2], f, all) + elseif op == "VARARG" then + -- R(A) B + i.A = R(v[1], f) + i.B = Int(v[2]) + i.C = 0 + f.is_vararg = 1 + f.numparams = i.B + elseif op == "EXTRAARG" then + -- Ax + local pop = codelist[k-1].op + if pop == "LOADKX" then + i.Ax = Kst(v[1], f) - 1 + elseif pop == "SETLIST" then + i.Ax = Int(v[1]) + else + error ("EXTRAARG not expected") + end + else + local str = string.format("%s not implemented\n", op) + error (str) + end + end +end + +local function sew_function(t, ast, all) + local name = ast[t.id].header.name + t.linedefined = 0 + t.lastlinedefined = 0 + t.numparams = ast[t.id].header.numparams + if name ~= "main" then + t.is_vararg = 0 + end + -- registers 0/1 are always valid + t.register = {} + t.register[0] = 0 + t.register[1] = 1 + t.maxstacksize = 2 + -- constants + t.sizek = 0 + t.k = {} + t.const = {} + -- functions + t.sizep = 0 + t.p = {} + t.func = {} + -- upvalues + if name ~= "main" then + t.sizeupvalues = 0 + t.upvalues = {} + t.upval = {} + end + t.sizelineinfo = 0 + t.sizelocvars = 0 + sew_code(t, ast, all) +end + +local function sew(t, ast) + if not t.main then error ("main not defined") end + -- main function always have upvalue _ENV defined + t.main.sizeupvalues = 1 + t.main.upval = {} + t.main.upval[ladconf.LUA_ENV] = 1 + t.main.upvalues = {} + t.main.upvalues[1] = {} + t.main.upvalues[1].instack = 1 + t.main.upvalues[1].idx = 0 + t.main.upvalues[1].name = ladconf.LUA_ENV + -- main is always vararg + t.main.is_vararg = 1 + for k,v in pairs(t) do + sew_function(v, ast, t) + end +end + +local function traverse(ast) + local t = converge(ast) + if not t then error("Empty File") end + sew(t, ast) + return t +end + +local function write_byte(output, byte) + if byte ~= 0 then + output:write(string.format("%c", byte)) + else + output:write('\0') + end +end + +local function get_hex(n) + return string.format("0x%x", n) +end + +local function get_int(i, s) + local x = get_hex(i) + local a,b = 0,8 + local t = {} + for k=1,s do + t[k] = ladconf.get_bit(x, a, b) + a = a + 8 + b = b + 8 + end + return t +end + +local function write_int(output, n, s) + local i = get_int(n, s) + for k=1,s do + write_byte(output, i[k]) + end +end + +local function write_string(output, str) + local len = string.len(str) + write_int(output, len + 1, ladconf.SIZE_T) + for i=1,len do + write_byte(output, string.byte(str, i)) + end + write_byte(output, 0) +end + +local function write_source_name(output, name) + write_string(output, name) +end + +local function get_byte(v) + return math.floor(v / 256), string.char(math.floor(v) % 256) +end + +local function convert_number(x) + local sign = 0 + if x < 0 then sign = 1; x = -x end + local mantissa, exponent = math.frexp(x) + if x == 0 then -- zero + mantissa, exponent = 0, 0 + else + mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53) + exponent = exponent + 1022 + end + local v, byte = {}, "" -- convert to bytes + x = mantissa + for i = 1,6 do + x, byte = get_byte(x); v[i] = string.byte(byte) + end + x, byte = get_byte(exponent * 16 + x); v[7] = string.byte(byte) + x, byte = get_byte(sign * 128 + x); v[8] = string.byte(byte) + return v +end + +local function write_number(output, n) + local t = convert_number(n) + for k=1,ladconf.LUA_NUMBER do write_byte(output, t[k]) end +end + +local function write_header(output) + for i=1,string.len(ladconf.LUA_SIGNATURE) do + write_byte(output, string.byte(ladconf.LUA_SIGNATURE, i)) + end + write_byte(output, ladconf.LUA_VERSION) + write_byte(output, ladconf.LUA_FORMAT) + write_byte(output, ladconf.ENDIANNESS) + write_byte(output, ladconf.INT) + write_byte(output, ladconf.SIZE_T) + write_byte(output, ladconf.INSTRUCTION) + write_byte(output, ladconf.LUA_NUMBER) + write_byte(output, ladconf.INTEGRAL) + for i=1,string.len(ladconf.LUAC_TAIL) do + write_byte(output, string.byte(ladconf.LUAC_TAIL, i)) + end +end + +local function write_function_values(output, f) + write_byte(output, f.numparams) + write_byte(output, f.is_vararg) + write_byte(output, f.maxstacksize) +end + +local function gen_iABC(O, A, B, C) + local field = {O, A, C, B} + local v, i = {}, 0 + local cValue, cBits, cPos = 0, 0, 1 + -- encode an instruction + while i < ladconf.INSTRUCTION do + -- if need more bits, suck in a field at a time + while cBits < 8 do + cValue = field[cPos] * math.ldexp(1, cBits) + cValue + cBits = cBits + ladconf.ABC[cPos]; cPos = cPos + 1 + end + -- extract bytes to instruction string + while cBits >= 8 do + v[i+1] = (cValue % 256) + cValue = math.floor(cValue / 256) + cBits = cBits - 8; i = i + 1 + end + end + return v +end + +local function gen_iABx(O, A, Bx) + return gen_iABC(O, A, math.floor(Bx / ladconf.MASK_C), (Bx % ladconf.MASK_C)) +end + +local function gen_iAsBx(O, A, sBx) + return gen_iABx(O, A, (sBx + ladconf.MAXARG_sBx)) +end + +local function gen_iAx(O, Ax) + return gen_iABC(O, Ax, 0, 0) +end + +local function write_instruction(output, i) + local m = ladconf.get_op_mode(i.O + 1) + local t = {} + + if m == ladconf.iABC then + t = gen_iABC(i.O, i.A, i.B, i.C) + elseif m == ladconf.iABx then + t = gen_iABx(i.O, i.A, i.Bx - 1) + elseif m == ladconf.iAsBx then + t = gen_iAsBx(i.O, i.A, i.sBx - 1) + elseif m == ladconf.iAx then + t = gen_iAx(i.O, i.Ax) + end + + for k=1,ladconf.INSTRUCTION do write_byte(output, t[k]) end +end + +local function write_code(output, f) + local n = f.sizecode + write_int(output, n, ladconf.INT) + for i=1,n do + write_instruction(output, f.code[i]) + end +end + +local function write_constant(output, k) + local t = k.k_type + write_byte(output, t) + if t == ladconf.LUA_TNIL then + -- do not need to write anything + elseif t == ladconf.LUA_TBOOLEAN then + elseif t == ladconf.LUA_TNUMBER then + write_number(output, k.value) + elseif t == ladconf.LUA_TSTRING then + write_string(output, k.value) + end +end + +local function write_constants(output, f) + local n + n = f.sizek + write_int(output, n, ladconf.INT) + for i=1,n do + write_constant(output, f.k[i]) + end +end + +local function write_upvalues(output, f) + local n = f.sizeupvalues + write_int(output, n, ladconf.INT) + for i=1,n do + write_byte(output, f.upvalues[i].instack) + write_byte(output, f.upvalues[i].idx) + end +end + +local function write_debug(output, f) + write_string(output, ladconf.LUA_SOURCE) + write_int(output, f.sizelineinfo, ladconf.INT) + write_int(output, f.sizelocvars, ladconf.INT) + local n = f.sizeupvalues + write_int(output, n, ladconf.INT) + for k=1,n do + write_string(output, f.upvalues[k].name) + end +end + +local function write_function(output, current, parsed) + write_int(output, current.linedefined, ladconf.INT) -- line defined + write_int(output, current.lastlinedefined, ladconf.INT) -- last line defined + write_function_values(output, current) + write_code(output, current) + write_constants(output, current, parsed) + n = current.sizep + write_int(output, n, ladconf.INT) + for i=1,n do + local name = current.p[i] + write_function(output, parsed[name], parsed) + end + write_upvalues(output, current) + write_debug(output, current) +end + +local function write_bytecode(output, parsed) + write_header(output) + write_function(output, parsed.main, parsed) +end + +local function write(filename, parsed) + local output = assert(io.open(filename, "wb")) + write_bytecode(output, parsed) + output:close() +end + +local assembler = { + parse = parse, + traverse = traverse, + write = write, + print_ast = print_ast, +} + +return assembler diff --git a/5.2/disassembler.lua b/5.2/disassembler.lua new file mode 100644 index 0000000..f3a19f3 --- /dev/null +++ b/5.2/disassembler.lua @@ -0,0 +1,754 @@ +local ladconf = require("ladconf") + +local function check_signature(bytecode) + local sig = string.format(string.format("%o", string.byte(bytecode, 1))) + sig = sig .. string.char(string.byte(bytecode, 2)) + sig = sig .. string.char(string.byte(bytecode, 3)) + sig = sig .. string.char(string.byte(bytecode, 4)) + sig = string.gsub(sig, "33", "\033") + if sig ~= ladconf.LUA_SIGNATURE then + error ("Not a Lua bytecode!") + end +end + +local function check_version(bytecode) + if string.byte(bytecode, 5) ~= ladconf.LUA_VERSION then + error ("Disassembler works only with Lua 5.2!") + end +end + +local function check_header(bytecode) + check_signature(bytecode) + check_version(bytecode) +end + +local function set_auto_flags(bytecode) + ladconf.ENDIANNESS = string.byte(bytecode, 7) + ladconf.INT = string.byte(bytecode, 8) + ladconf.SIZE_T = string.byte(bytecode, 9) + ladconf.INSTRUCTION = string.byte(bytecode, 10) + ladconf.LUA_NUMBER = string.byte(bytecode, 11) + ladconf.INTEGRAL = string.byte(bytecode, 12) +end + +local function parse_int(bytecode, k, n) + local i = "0x" + local s,e = k + (n-1), k + 1 + for p=s,e,-1 do + i = i .. string.format("%02x", string.byte(bytecode, p)) + end + i = i .. string.format("%02x", string.byte(bytecode, k)) + return tonumber(i),k + (n-1) +end + +local function parse_instruction(bytecode, k) + local code = "0x" + local n = k + (ladconf.INSTRUCTION - 1) + for i=n,k,-1 do + code = code .. string.format("%02x", string.byte(bytecode, i)) + end + return code,k + (ladconf.INSTRUCTION - 1) +end + +local function parse_code(bytecode, k, parsed) + parsed.sizecode,k = parse_int(bytecode, k, ladconf.INT) + parsed.code = {} + for i=1,parsed.sizecode do + parsed.code[i],k = parse_instruction(bytecode, k + 1) + end + return k +end + +local function setnilvalue(parsed) + parsed.type = ladconf.LUA_TNIL + parsed.value = 'nil' +end + +local function setbvalue(parsed, boolean) + parsed.type = ladconf.LUA_TBOOLEAN + if boolean == 0 then + parsed.value = 'false' + end + parsed.value = 'true' +end + +local function setnvalue(parsed, number) + parsed.type = ladconf.LUA_TNUMBER + parsed.value = number +end + +local function iscntrl(x) + if (x >= 0 and x <= 31) or (x == 127) then return true end + return false +end + +local function isprint(x) + return not iscntrl(x) +end + +local function fixed_string(str) + local new_str = "" + for i=1,string.len(str) do + char = string.byte(str, i) + if char == 34 then new_str = new_str .. string.format("\\\"") + elseif char == 92 then new_str = new_str .. string.format("\\\\") + elseif char == 7 then new_str = new_str .. string.format("\\a") + elseif char == 8 then new_str = new_str .. string.format("\\b") + elseif char == 12 then new_str = new_str .. string.format("\\f") + elseif char == 10 then new_str = new_str .. string.format("\\n") + elseif char == 13 then new_str = new_str .. string.format("\\r") + elseif char == 9 then new_str = new_str .. string.format("\\t") + elseif char == 11 then new_str = new_str .. string.format("\\v") + else + if isprint(char) then + new_str = new_str .. string.format("%c", char) + else + new_str = new_str .. string.format("\\%03d", char) + end + end + end + return new_str +end + +local function setsvalue(parsed, string) + parsed.type = ladconf.LUA_TSTRING + parsed.value = fixed_string(string) +end + +local function parse_number(bytecode, k) + sign = 1 + mantissa = string.byte(bytecode, k+6) % 16 + for i=k+5,k,-1 do mantissa = mantissa * 256 + string.byte(bytecode, i) end + if string.byte(bytecode,k+7) > 127 then sign = -1 end + exponent = (string.byte(bytecode, k+7) % 128) * 16 + math.floor(string.byte(bytecode, k+6) / 16) + if exponent == 0 then return 0 end + mantissa = (math.ldexp(mantissa, -52) + 1) * sign + return math.ldexp(mantissa, exponent - 1023) +end + +local function parse_string(bytecode, k, len) + local str = "" + for i=k+1,k+(len-1) do + local byte = string.byte(bytecode, i) + if byte ~= 0 then + str = str .. string.char(byte) + else + str = str .. '\0' + end + end + return str +end + +local function parse_constants(bytecode, k, parsed) + parsed.sizek,k = parse_int(bytecode, k, ladconf.INT) + parsed.k = {} + for i=1,parsed.sizek do + k = k + 1 + local t = string.byte(bytecode, k) + parsed.k[i] = {} + if t == ladconf.LUA_TNIL then + setnilvalue(parsed.k[i]) + elseif t == ladconf.LUA_TBOOLEAN then + k = k + 1 + setbvalue(parsed.k[i], string.byte(bytecode, k)) + elseif t == ladconf.LUA_TNUMBER then + setnvalue(parsed.k[i], parse_number(bytecode, k + 1)) + k = k + ladconf.LUA_NUMBER + elseif t == ladconf.LUA_TSTRING then + local len + len,k = parse_int(bytecode, k + 1, ladconf.SIZE_T) + setsvalue(parsed.k[i], parse_string(bytecode, k, len)) + k = k + len + end + end + return k +end + +local function parse_upvalues(bytecode, k, parsed) + parsed.sizeupvalues,k = parse_int(bytecode, k, ladconf.INT) + parsed.upvalues = {} + for i=1,parsed.sizeupvalues do + parsed.upvalues[i] = {} + parsed.upvalues[i].instack = string.byte(bytecode, k + 1) + parsed.upvalues[i].idx = string.byte(bytecode, k + 2) + k = k + 2 + end + return k +end + +local function parse_debug(bytecode, k, parsed) + local len,n + len,k = parse_int(bytecode, k, ladconf.SIZE_T) + parsed.source = parse_string(bytecode, k + 1, len) + k = k + len + parsed.sizelineinfo,k = parse_int(bytecode, k + 1, ladconf.INT) + parsed.lineinfo = {} + for i=1,parsed.sizelineinfo do + parsed.lineinfo[i],k = parse_int(bytecode, k + 1, ladconf.INT) + end + parsed.sizelocvars,k = parse_int(bytecode, k + 1, ladconf.INT) + parsed.locvars = {} + for i=1,parsed.sizelocvars do + parsed.locvars[i] = {} + len,k = parse_int(bytecode, k + 1, ladconf.SIZE_T) + parsed.locvars[i].varname = parse_string(bytecode, k, len) + k = k + len + parsed.locvars[i].startpc,k = parse_int(bytecode, k + 1, ladconf.INT) + parsed.locvars[i].endpc,k = parse_int(bytecode, k + 1, ladconf.INT) + end + n,k = parse_int(bytecode, k + 1, ladconf.INT) + for i=1,n do + len,k = parse_int(bytecode, k + 1, ladconf.SIZE_T) + parsed.upvalues[i].name = parse_string(bytecode, k, len) + k = k + len + end + return k +end + +local function parse_function(bytecode, k, parsed) + parsed.linedefined,k = parse_int(bytecode, k + 1, ladconf.INT) + parsed.lastlinedefined,k = parse_int(bytecode, k + 1, ladconf.INT) + parsed.numparams,k = string.byte(bytecode, k + 1), k + 1 + parsed.is_vararg,k = string.byte(bytecode, k + 1), k + 1 + parsed.maxstacksize,k = string.byte(bytecode, k + 1), k + 1 + k = parse_code(bytecode, k + 1, parsed) + k = parse_constants(bytecode, k + 1, parsed) + parsed.sizep,k = parse_int(bytecode, k + 1, ladconf.INT) + parsed.p = {} + for i=1,parsed.sizep do + parsed.p[i] = {} + parsed.p[i].parent = parsed.id + parsed.p[i].id = i + k = parse_function(bytecode, k, parsed.p[i]) + end + k = parse_upvalues(bytecode, k + 1, parsed) + k = parse_debug(bytecode, k + 1, parsed) + return k +end + +local function parse(bytecode) + local parsed = {} + set_auto_flags(bytecode) + parsed.id = 0 + parse_function(bytecode, ladconf.LUAC_HEADERSIZE, parsed) + return parsed +end + +local function get_opcode(i) + return ladconf.get_bit(i, ladconf.POS_OP, ladconf.SIZE_OP) + 1 +end + +local function getarg_A(i) + return ladconf.get_bit(i, ladconf.POS_A, ladconf.SIZE_A) +end + +local function getarg_B(i) + return ladconf.get_bit(i, ladconf.POS_B, ladconf.SIZE_B) +end + +local function getarg_C(i) + return ladconf.get_bit(i, ladconf.POS_C, ladconf.SIZE_C) +end + +local function getarg_Bx(i) + return ladconf.get_bit(i, ladconf.POS_Bx, ladconf.SIZE_Bx) +end + +local function getarg_Ax(i) + return ladconf.get_bit(i, ladconf.POS_Ax, ladconf.SIZE_Ax) +end + +local function getarg_sBx(i) + return getarg_Bx(i) - ladconf.MAXARG_sBx +end + +local function get_b_mode(o) + return ladconf.opmodes[o].B +end + +local function get_c_mode(o) + return ladconf.opmodes[o].C +end + +local function ISK(x) + return ladconf.ISK(x) +end + +local function INDEXK(x) + return ladconf.INDEXK(x) +end + +local function MYK(x) + return (-1-(x)) +end + +local function UPVALNAME(parsed, x) + if parsed.upvalues[x].name then + return parsed.upvalues[x].name + end + return "-" +end + +local function get_funcline(parsed, pc) + if parsed.sizelineinfo > 0 then + return parsed.lineinfo[pc] + end + return 0 +end + +local function print_header(parsed) + local function SS(x) if x == 1 then return "" else return "s" end end + local function S(x) return x,SS(x) end + + local func_name = "function" + local is_vararg = "" + + if parsed.linedefined == 0 and parsed.id == 0 then + func_name = "main" + end + if parsed.is_vararg ~= 0 then + is_vararg = "+" + end + + io.write(string.format("\n%s <%s:%d,%d> (%d instruction%s at %d)\n", + func_name, parsed.source, + parsed.linedefined, parsed.lastlinedefined, + parsed.sizecode, SS(parsed.sizecode), 0)) + io.write(string.format("%d%s param%s, %d slot%s, %d upvalue%s, ", + parsed.numparams, is_vararg, SS(parsed.numparams), + parsed.maxstacksize, SS(parsed.maxstacksize), + parsed.sizeupvalues, SS(parsed.sizeupvalues))) + io.write(string.format("%d local%s, %d constant%s, %d function%s\n", + parsed.sizelocvars, SS(parsed.sizelocvars), + parsed.sizek, SS(parsed.sizek), + parsed.sizep, SS(parsed.sizep))) +end + +local function print_string(str) + io.write(string.format('"%s"', str)) +end + +local function print_constant(parsed, i) + if not parsed.k[i] then + io.write("nil") + return + end + local t = parsed.k[i].type + local v = parsed.k[i].value + if t == ladconf.LUA_TNIL or + t == ladconf.LUA_TBOOLEAN or + t == ladconf.LUA_TNUMBER then + io.write(string.format("%s", v)) + elseif t == ladconf.LUA_TSTRING then + print_string(v) + end +end + +local function print_code(parsed) + local n = parsed.sizecode + local pc = 1 + while pc <= n do + local i = parsed.code[pc] + local o = get_opcode(i) + local a = getarg_A(i) + local b = getarg_B(i) + local c = getarg_C(i) + local ax = getarg_Ax(i) + local bx = getarg_Bx(i) + local sbx = getarg_sBx(i) + local line = get_funcline(parsed, pc) + local opcode = ladconf.OPCODE[o] + + io.write(string.format("\t%d\t", pc)) + if line > 0 then + io.write(string.format("[%d]\t", line)) + else + io.write(string.format("[-]\t")) + end + io.write(string.format("%-9s\t", opcode)) + + local opmode = ladconf.get_op_mode(o) + if opmode == ladconf.iABC then + io.write(string.format("%d", a)) + local bmode = get_b_mode(o) + local cmode = get_c_mode(o) + if bmode ~= ladconf.OpArgN then + if ISK(b) then + io.write(string.format(" %d", MYK(INDEXK(b)))) + else + io.write(string.format(" %d", b)) + end + end + if cmode ~= ladconf.OpArgN then + if ISK(c) then + io.write(string.format(" %d", MYK(INDEXK(c)))) + else + io.write(string.format(" %d", c)) + end + end + elseif opmode == ladconf.iABx then + io.write(string.format("%d", a)) + local bmode = get_b_mode(o) + if bmode == ladconf.OpArgK then + io.write(string.format(" %d", MYK(bx))) + end + if bmode == ladconf.OpArgU then + io.write(string.format(" %d", bx)) + end + elseif opmode == ladconf.iAsBx then + io.write(string.format("%d %d", a, sbx)) + elseif opmode == ladconf.iAx then + io.write(string.format("%d", MYK(ax))) + end + + if opcode == "LOADK" then + io.write(string.format("\t; ")) + print_constant(parsed, bx+1) + elseif opcode == "GETUPVAL" or + opcode == "SETUPVAL" then + io.write(string.format("\t; %s", UPVALNAME(parsed, b+1))) + elseif opcode == "GETTABUP" then + io.write(string.format("\t; %s", UPVALNAME(parsed, b+1))) + if ISK(c) then + io.write(string.format(" ")) + print_constant(parsed, INDEXK(c+1)) + end + elseif opcode == "SETTABUP" then + io.write(string.format("\t; %s", UPVALNAME(parsed, a+1))) + if ISK(b) then + io.write(string.format(" ")) + print_constant(parsed, INDEXK(b+1)) + end + if ISK(c) then + io.write(string.format(" ")) + print_constant(parsed, INDEXK(c+1)) + end + elseif opcode == "GETTABLE" or + opcode == "SELF" then + if ISK(c) then + io.write(string.format("\t; ")) + print_constant(parsed, INDEXK(c+1)) + end + elseif opcode == "SETTABLE" or + opcode == "ADD" or + opcode == "SUB" or + opcode == "MUL" or + opcode == "DIV" or + opcode == "POW" or + opcode == "EQ" or + opcode == "LT" or + opcode == "LE" then + if ISK(b) or ISK(c) then + io.write(string.format("\t; ")) + if ISK(b) then + print_constant(parsed, INDEXK(b+1)) + else + io.write(string.format("-")) + end + io.write(string.format(" ")) + if ISK(c) then + print_constant(parsed, INDEXK(c+1)) + else + io.write(string.format("-")) + end + end + elseif opcode == "JMP" or + opcode == "FORLOOP" or + opcode == "FORPREP" or + opcode == "TFORLOOP" then + io.write(string.format("\t; to %d", sbx+pc+1)) + elseif opcode == "CLOSURE" then + io.write(string.format("\t; 0x")) + elseif opcode == "SETLIST" then + if c == 0 then + pc = pc + 1 + io.write(string.format("\t; %d", parsed.code[pc])) + else + io.write(string.format("\t; %d", c)) + end + elseif opcode == "EXTRAARG" then + io.write(string.format("\t; ")) + print_constant(parsed, ax+1) + end + io.write(string.format("\n")) + pc = pc + 1 + end +end + +local function print_debug(parsed) + local n + n = parsed.sizek + io.write(string.format("constants (%d) for 0:\n", n)) + for i=1,n do + io.write(string.format("\t%d\t", i)) + print_constant(parsed, i) + io.write(string.format("\n")) + end + n = parsed.sizelocvars + io.write(string.format("locals (%d) for 0:\n", n)) + for i=1,n do + io.write(string.format("\t%d\t%s\t%d\t%d\n", i-1, + parsed.locvars[i].varname, + parsed.locvars[i].startpc+1, + parsed.locvars[i].endpc+1)) + end + n = parsed.sizeupvalues + io.write(string.format("upvalues (%d) for 0:\n", n)) + for i=1,n do + io.write(string.format("\t%d\t%s\t%d\t%d\n", i-1, + UPVALNAME(parsed, i), + parsed.upvalues[i].instack, + parsed.upvalues[i].idx)) + end +end + +local function print_function(parsed, full) + local n = parsed.sizep + print_header(parsed) + print_code(parsed) + if full then print_debug(parsed) end + for i=1,n do + print_function(parsed.p[i], full) + end +end + +local function write_header(output, parsed) + local fname + local np = parsed.numparams + if parsed.linedefined == 0 and parsed.id == 0 then + fname = "main" + else + fname = string.format("F_%s_%s", parsed.parent, parsed.id) + end + output:write(string.format("\nfunction %s(%s):\n", fname, np)) +end + +local function write_par(output, x) + output:write(string.format("%s", x)) +end + +local function write_sep(output) + output:write(string.format(", ")) +end + +local function R(x) + return "$" .. x +end + +local function UpValue(parsed, x) + return parsed.upvalues[x+1].name +end + +local function KST(parsed, x) + return parsed.k[x+1].value +end + +local function Kst(parsed, x) + local t = parsed.k[x+1].type + local v = parsed.k[x+1].value + if t == ladconf.LUA_TNIL or + t == ladconf.LUA_TBOOLEAN or + t == ladconf.LUA_TNUMBER then + return v + elseif t == ladconf.LUA_TSTRING then + return '"' .. v .. '"' + end +end + +local function RKST(parsed, x) + if ISK(x) then + return KST(parsed, INDEXK(x)) + else + return R(x) + end +end + +local function RK(parsed, x) + if ISK(x) then + return Kst(parsed, INDEXK(x)) + else + return R(x) + end +end + +local function KPROTO(parsed, x) + local parent = parsed.p[x+1].parent + local id = parsed.p[x+1].id + return string.format("F_%s_%s", parent, id) +end + +local function write_code(output, parsed) + local n = parsed.sizecode + for pc=1,n do + local i = parsed.code[pc] + local o = get_opcode(i) + local a = getarg_A(i) + local b = getarg_B(i) + local c = getarg_C(i) + local ax = getarg_Ax(i) + local bx = getarg_Bx(i) + local sbx = getarg_sBx(i) + local line = get_funcline(parsed, pc) + local opcode = ladconf.OPCODE[o] + + output:write(string.format("\t%d\t", pc)) + output:write(string.format("[%d]\t", line)) + output:write(string.format("%-9s\t", opcode)) + + if opcode == "MOVE" or + opcode == "UNM" or + opcode == "NOT" or + opcode == "LEN" then + -- R(A) R(B) + write_par(output, R(a)) + write_sep(output) + write_par(output, R(b)) + elseif opcode == "LOADK" then + -- R(A) Kst(Bx) + write_par(output, R(a)) + write_sep(output) + write_par(output, Kst(parsed, bx)) + elseif opcode == "LOADKX" then + -- R(A) + write_par(output, R(a)) + elseif opcode == "LOADBOOL" or + opcode == "NEWTABLE" or + opcode == "CALL" or + opcode == "TAILCALL" or + opcode == "SETLIST" then + -- R(A) B C + write_par(output, R(a)) + write_sep(output) + write_par(output, b) + write_sep(output) + write_par(output, c) + elseif opcode == "LOADNIL" or + opcode == "RETURN" or + opcode == "VARARG" then + -- R(A) B + write_par(output, R(a)) + write_sep(output) + write_par(output, b) + elseif opcode == "GETUPVAL" or + opcode == "SETUPVAL" then + -- R(A) UpValue(B) + write_par(output, R(a)) + write_sep(output) + write_par(output, UpValue(parsed, b)) + elseif opcode == "GETTABUP" then + -- R(A) UpValue(B) RK(C) + write_par(output, R(a)) + write_sep(output) + write_par(output, UpValue(parsed, b)) + write_sep(output) + write_par(output, RK(parsed, c)) + elseif opcode == "GETTABLE" or + opcode == "SELF" then + -- R(A) R(B) RK(C) + write_par(output, R(a)) + write_sep(output) + write_par(output, R(b)) + write_sep(output) + write_par(output, RK(parsed, c)) + elseif opcode == "SETTABUP" then + -- UpValue(A) RK(B) RK(C) + write_par(output, UpValue(parsed, a)) + write_sep(output) + write_par(output, RK(parsed, b)) + write_sep(output) + write_par(output, RK(parsed, c)) + elseif opcode == "SETTABLE" or + opcode == "ADD" or + opcode == "SUB" or + opcode == "MUL" or + opcode == "DIV" or + opcode == "MOD" or + opcode == "POW" then + -- R(A) RK(B) RK(C) + write_par(output, R(a)) + write_sep(output) + write_par(output, RK(parsed, b)) + write_sep(output) + write_par(output, RK(parsed, c)) + elseif opcode == "CONCAT" then + -- R(A) R(B) R(C) + write_par(output, R(a)) + write_sep(output) + write_par(output, R(b)) + write_sep(output) + write_par(output, R(c)) + elseif opcode == "JMP" then + -- A sBx + write_par(output, a) + write_sep(output) + write_par(output, sbx + pc + 1) + elseif opcode == "EQ" or + opcode == "LT" or + opcode == "LE" then + -- A RK(B) RK(C) + write_par(output, a) + write_sep(output) + write_par(output, RK(parsed, b)) + write_sep(output) + write_par(output, RK(parsed, c)) + elseif opcode == "TEST" or + opcode == "TFORCALL" then + -- R(A) C + write_par(output, R(a)) + write_sep(output) + write_par(output, c) + elseif opcode == "TESTSET" then + -- R(A) R(B) C + write_par(output, R(a)) + write_sep(output) + write_par(output, R(b)) + write_sep(output) + write_par(output, c) + elseif opcode == "FORLOOP" or + opcode == "FORPREP" or + opcode == "TFORLOOP" then + -- R(A) sBx + write_par(output, R(a)) + write_sep(output) + write_par(output, sbx + pc + 1) + elseif opcode == "CLOSURE" then + -- R(A) KPROTO(Bx) + write_par(output, R(a)) + write_sep(output) + write_par(output, KPROTO(parsed, bx)) + elseif opcode == "EXTRAARG" then + -- Ax + po = get_opcode(parsed.code[pc-1]) + popcode = ladconf.OPCODE[po] + if popcode == "LOADKX" then + write_par(output, Kst(parsed, ax)) + elseif popcode == "SETLIST" then + write_par(output, ax) + end + end + output:write(string.format("\n")) + end +end + +local function write_function(output, parsed) + local n = parsed.sizep + write_header(output, parsed) + write_code(output, parsed) + for i=1,n do + write_function(output, parsed.p[i]) + end +end + +local function write(filename, parsed) + local output = assert(io.open(filename, "w")) + write_function(output, parsed) + output:close() +end + +local disassembler = { + parse = parse, + write = write, + print_function = print_function, +} + +return disassembler diff --git a/5.2/doc/fat_rec.asm b/5.2/doc/fat_rec.asm new file mode 100644 index 0000000..ce93373 --- /dev/null +++ b/5.2/doc/fat_rec.asm @@ -0,0 +1,23 @@ + +function main(0): + CLOSURE $0, fat + SETTABUP _ENV, fat, $0 + GETTABUP $0, _ENV, print + GETTABUP $1, _ENV, fat + LOADK $2, 5 + CALL $1, 2, 0 + CALL $0, 0, 1 + RETURN $0, 1 + +function fat(1): + EQ 0, $0, 0 + JMP 0, label1 ; jump to label1 + LOADK $1, 1 + RETURN $1, 2 +label1: GETTABUP $1, _ENV, fat ; create label1 + SUB $2, $0, 1 + CALL $1, 2, 2 + MUL $1, $0, $1 + RETURN $1, 2 + RETURN $0, 1 + diff --git a/5.2/doc/hello.asm b/5.2/doc/hello.asm new file mode 100644 index 0000000..57c046c --- /dev/null +++ b/5.2/doc/hello.asm @@ -0,0 +1,6 @@ + +function main(0): + 1 [1] GETTABUP $0, _ENV, "print" + 2 [1] LOADK $1, "hello world!" + 3 [1] CALL $0, 2, 1 + 4 [1] RETURN $0, 1 diff --git a/5.2/doc/hello.lua b/5.2/doc/hello.lua new file mode 100644 index 0000000..a50a5fc --- /dev/null +++ b/5.2/doc/hello.lua @@ -0,0 +1 @@ +print ("hello world!") diff --git a/5.2/doc/logo1.png b/5.2/doc/logo1.png new file mode 100644 index 0000000000000000000000000000000000000000..714be3d6dcfec6391adc84b9bd0645d3ad253525 GIT binary patch literal 11125 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 E0H=rgJpcdz literal 0 HcmV?d00001 diff --git a/5.2/doc/manual.html b/5.2/doc/manual.html new file mode 100644 index 0000000..7a2f0f4 --- /dev/null +++ b/5.2/doc/manual.html @@ -0,0 +1,869 @@ + + + + +Lua Assembler/Disassembler + + + +
+ +
+

Description

+ +

Lua Assembler/Disassembler is a tool that can be used to generate Lua bytecode and Assembly code. +Lua bytecode is generated through the assembler provided, while Assembly code is generated by the disassembler, +which inspects Lua bytecode in order to reproduce it into an Assembly language. + +The assembler uses Lpeg in order to implement the parser +for our Assembly syntax, which is presented on this document. +

+ +
+ +

Requirements

+Lua Assembler/Disassembler is compatible with Lua version 5.2.0 and Lpeg version 0.10.2. +
+ +

Install

+

+To run Lua Assembler/Disassembler in your computer, first you need install the +Lua language and the +Lpeg library. +The Lua Assembler/Disassembler may be executed as an application/script and +can be used as a module in your Lua code too. +In order to install, please, download the source code, extract it and then +follow below instructions to have the applications/scripts and modules installed. +

+

Installing scripts

+

+Just copy the following files to a directory in your computer or +to your $PATH (which will depend on the operating system). +

+
    +
  • luaa.lua
  • +
  • luad.lua
  • +
+

+Since the applications/scripts use the modules to run assembler and disassembler +functions, please, do not forget to follow below steps in order to get them installed. +

+ +

Installing modules

+

+Just copy the following files to the first directory that is set in package.path. +

+
    +
  • assembler.lua
  • +
  • disassembler.lua
  • +
  • ladconf.lua
  • +
+

+You can also copy above files to other directory, if that's the case, please, do not +forget to change package.path, in your Lua code, in order to look for the modules +in the directory that you have installed them. +

+
+ +

Assembler

+

+The assembler might be used as a stand alone application/script or as a module that +you require in your code. +

+ +

Assembler script

+The stand alone application/script is called luaa.lua. + +The following synopsis should be used: + +
+lua luaa.lua [options] [filename]
+
+ +

Available options are listed below and must be separate.

+ +

-h

+

+Just prints a help message listing all available options and a brief explanation about them. +

+ +

-o file

+

+Output to file, instead of the default luaa.out. +Be careful to not overwrite precious files since you might specify the output file as an existent source file. +

+ +

Assembler module

+

+The module is called assembler and something like below line should be used in order to make +its functions available. +

+
+local assembler = require("assembler")
+
+

Available functions are listed below.

+ +

assembler.parse(contents)

+

+The function parse gets the contents of an Assembly source code as its only +argument and returns its Abstract Syntax Tree (AST). +

+

assembler.traverse(ast)

+

+The function traverse gets the AST, returned by parse function, and inspects +the AST to find errors. If no errors were found, than all information inside +the AST are combined into a table that will be used to write the correspondent +Lua bytecode. +

+

assembler.write(filename, parsed)

+

+The function write gets two parameters: the first one is the filename were +Lua bytecode should be written, while the second one is the table returned +by traverse function. +

+

assembler.print_ast(ast)

+

+The function print_ast might be used for debug purposes. It receives the AST +as its only parameters and prints it. +

+ +
+ +

Disassembler

+

+The disassembler might be used as a stand alone application/script or as a module that +you require in your code. +

+ +

Disassembler script

+The stand alone application/script is called luad.lua. + +The following synopsis should be used: + +
+lua luad.lua [options] [filename]
+
+ +

Available options are listed below and must be separate.

+ +

-h

+

+Just prints a help message listing all available options and a brief explanation about them. +

+

-l

+

+Produce a listing of the compiled bytecode for Lua's virtual machine on luac -l style. +Use -l -l for full listing. +

+

-o file

+

+Output to file, instead of the default luad.asm. +Be careful to not overwrite precious files since you might specify the output file as an existent source file. +

+ +

Disassembler module

+

+The module is called disassembler and something like below line should be used in order to make +its functions available. +

+
+local disassembler = require("disassembler")
+
+

Available functions are listed below.

+ +

disassembler.parse(bytecode)

+The function parse gets a chunk of Lua bytecode as its only +argument and returns a table containing all information that +are necessary to write its correspondent Assembly code. +

+

+

disassembler.write(filename, parsed)

+The function write gets two parameters: the first one is the filename were +the Assembly code should be written, while the second one is the table returned +by parse function. +

+

+

disassembler.print_function(parsed, full)

+

+The function print_function might be used for printing Lua bytecode in luac -l style. +It has two parameters: the first one is the table returned by parse function and +the second one is a boolean value indication if full listing is expected or not. +

+ +
+ +

How To Use

+ +

The following command line shows how to use the disassembler in order to generate the assembly code +for a Lua source file: +

+$ lua luad.lua -o hello.asm hello.lua
+
+ +The above command line outputs hello.asm which contains the assembly code for hello.lua. +

+It is important to remember that the disassembler can be used with a Lua bytecode too, as we shown below: +
+$ lua luad.lua luac.out
+
+ +Notice that in this case we haven't specified the output file, in this way the output will be the default luadd.asm. +

+

The following command line shows how to use the assembler in order to generate Lua bytecode from +our assembly code: +

+$ lua luaa.lua -o hello.out hello.asm
+
+ +The above command line outputs hello.out which contains Lua bytecode for hello.asm and can be executed using lua. +

+It is important to remember that if you do not specify the output file, then Lua bytecode will be generated as luaa.out by default. + +
+ +

Examples

+ +In this section we show some examples of our assembly language. The complete syntax can be checked +at Assembly Syntax as well as opcodes can be checked at Instructions. + +Here we show the assembly code that were generated, on above section, for hello.lua which is a simple +hello world program. + +
+function main(0):
+        1       [1]     GETTABUP        $0, _ENV, "print"
+        2       [1]     LOADK           $1, "hello world!"
+        3       [1]     CALL            $0, 2, 1
+        4       [1]     RETURN          $0, 1
+
+ +Once we use the assembler to output the Lua bytecode we can execute it using lua, as follows: + +
+$ lua hello.out
+hello world!
+$
+
+ +Now we define a recursive factorial in our Assembly language. Notice that line number and +source line number are not needed when we are writting the Assembly code. However, they are +generated when the disassembler process is performed. + +
+function main(0):
+        CLOSURE         $0, fat
+        SETTABUP        _ENV, fat, $0
+        GETTABUP        $0, _ENV, print
+        GETTABUP        $1, _ENV, fat
+        LOADK           $2, 5
+        CALL            $1, 2, 0
+        CALL            $0, 0, 1
+        RETURN          $0, 1
+
+function fat(1):
+        EQ              0, $0, 0
+        JMP             0, label1 ; jump to label1
+        LOADK           $1, 1
+        RETURN          $1, 2
+label1: GETTABUP        $1, _ENV, fat ; create label1
+        SUB             $2, $0, 1
+        CALL            $1, 2, 2
+        MUL             $1, $0, $1
+        RETURN          $1, 2
+        RETURN          $0, 1
+
+ +Notice that we have used a label in fat function since it is easier to check where to jump +when we are writing manual assembly code. +Also notice that a comment starts with a semicolon (;) and finishes at the end of the line. +A function main is necessary for all Assembly codes and the number of +parameters for the function that is being defined should be specified between +parenthesis. + +
+ +

Assembly Syntax

+ +Here is the complete syntax of Assembly in lpeg re module. + +
+  prog <- s function* !.
+  function <- header codelist
+  header <- "function" s name s "(" s n s ")" s ":" s
+  codelist <- code+
+  code <- autocode / manualcode
+  autocode <- n s ln s op s param s ("," s param s)*
+  manualcode <- (label s)? op s param s ("," s param s)*
+  n <- %d+
+  label <- name ":"
+  name <- !reserved {[a-zA-Z_][a-zA-Z0-9_]*}
+  ln <- "[" %d+ "]"
+  op <- !reserved %a+
+  param <- register / number / string
+  register <- "$" n
+  number <- hex / float / int
+  string <- name / shortstr
+  shortstr <- '"' ('\\' / '\"' / !'"' .)* '"' / "'" ("\\" / "\'" / !"'" .)* "'"
+  hex <- "-"? "0" [xX] %x+
+  float <- "-"? ( (%d+ "." %d* / "." %d+) e? / %d+ e )
+  e <- [eE] [+-]? n
+  int <- "-"? n
+  s <- (space / comment)*
+  space <- %s+
+  comment <- ";" (!%nl .)*
+  reserved <- "function"
+
+
+ +

Instructions

+ +

+We have four main types of instructions, they are so called iABC, iABx , iAsBx +and iAx. The instructions should be used as follows: +

+ +
+ + + + + + + + + + + + + + + + + + + + + +
Instruction typePattern
iABCOPCODE A, B, C
iABxOPCODE A, Bx
iAsBxOPCODE A, sBx
iAxOPCODE Ax
+
+ +

+Some iABC instructions do not use argument B or C and below we specify when that is the case. +Nonetheless, most of the iABC instructions follow the pattern described in above table. +

+ +

+It is also important to keep in mind that parameters should comply with the Assembly Syntax. +Here a some examples: +

+ +
+ + + + + + + + + + + + + + + + + + + + + + +
Parameter typeExample
Register$0, $1, $2, ...
Number0, 1, 2, ... / -1, -2, ... / 0.1, 0.2, ..., 1.0, 1.1, ... / -0.1, -0.2, ..., -1.0, -1,1, ...
NameF_0_1, blah, foo, ...
String"oi, tudo bem?", "hello world", "%s, string", ...
+
+ +

+We will use a instruction notation as follows to show how to use each opcode. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NotationMeaning
R(A), R(B), R(C)Register specified in field A, B or C.
PCProgram Counter.
Kst(k)A constant k that will be translated to a number.
Upvalue(name)An upvalue name that will be translated to a number.
RK(B), RK(C)A field that could be a register or a constant.
sBxSignal displacement for all kinds of jumps. It can be a number or a label.
KPROTO(name)A function name that will be used to create its closure.
+
+ +

+Below we show each opcode that is available in our assembly language as well as their respective arguments. +

+ +

MOVE R(A), R(B)

+R(A) := R(B) +

+Copies the value of register R(B) into register R(A). +

+

LOADK R(A), Kst(Bx)

+R(A) := Kst(Bx) +

+Loads constant Kst(Bx) into register R(A). Constants can be numbers or strings. +

+

LOADKX R(A)

+R(A) := Kst(extra arg) +

+Loads extra arg into register R(A). +The next instruction is always EXTRAARG. +

+

LOADBOOL R(A), B, C

+R(A) := (Bool)B; if (C) pc++ +

+Loads a boolean value B (1 for TRUE or 0 for FALSE should be used as B) into register R(A). +If C is not zero then next instruction is skipped. +

+

LOADNIL R(A), B

+R(A), R(A+1), ..., R(A+B) := nil +

+Sets to nil a range of registers from register R(A) up to B. +

+

GETUPVAL R(A), UpValue(B)

+R(A) := UpValue[B] +

+Copies the value in UpValue[B] into register R(A). +

+

GETTABUP R(A), UpValue(B), RK(C)

+R(A) := UpValue[B][RK(C)] +

+Copies the value of field RK(C), from table UpValue[B], into register R(A). +Note that if you are getting globals, then UpValue(B) should be _ENV. +

+

GETTABLE R(A), R(B), RK(C)

+R(A) := R(B)[RK(C)] +

+Copies the value from a table element into register R(A). +The table is referenced by register R(B), while the index to the table is given by +RK(C), which may be register R(C) or a constant Kst(C). +

+

SETTABUP UpValue(A), RK(B), RK(C)

+UpValue[A][RK(B)] := RK(C) +

+Copies the value of RK(C) to the field RK(B) of table UpValue[A]. +Note that if you are setting globals, then UpValue(A) should be _ENV. +

+

SETUPVAL R(A), UpValue(B)

+UpValue[B] := R(A) +

+Copies the value from register R(A) into UpValue[B]. +

+

SETTABLE R(A), RK(B), RK(C)

+R(A)[RK(B)] := RK(C) +

+Copies the value from register R(C) or constant Kst(C) into a table element. +The table is referenced by register R(A), while the index to the table is given by +RK(B), which may be register R(B) or a constant Kst(B). +

+

NEWTABLE R(A), B, C

+R(A) := {} (size = B,C) +

+Creates a new empty table at register R(A). +Argument B is the size of the array part, while C is the size of the hash part. +

+

SELF R(A), R(B), RK(C)

+R(A+1) := R(B); R(A) := R(B)[RK(C)] +

+It is used for object-oriented programming using tables. +Retrieves a function reference from a table element and places it in register R(A), +then a reference to the table itself is placed in the next register R(A+1). +R(B) is the register holding the reference to the table with the method, +while the method function is found using the table index RK(C), that can be +a register R(C) or a constant Kst(C). +

+

ADD R(A), RK(B), RK(C)

+R(A) := RK(B) + RK(C) +

+Adds RK(B) and RK(C) and holds the result into register R(A). +Both RK(B) and RK(C) may be either registers or constants. +

+

SUB R(A), RK(B), RK(C)

+R(A) := RK(B) - RK(C) +

+Subtracts RK(B) and RK(C) and holds the result into register R(A). +Both RK(B) and RK(C) may be either registers or constants. +

+

MUL R(A), RK(B), RK(C)

+R(A) := RK(B) * RK(C) +

+Multiplies RK(B) and RK(C) and holds the result into register R(A). +Both RK(B) and RK(C) may be either registers or constants. +

+

DIV R(A), RK(B), RK(C)

+R(A) := RK(B) / RK(C) +

+Divides RK(B) and RK(C) and holds the result into register R(A). +Both RK(B) and RK(C) may be either registers or constants. +

+

MOD R(A), RK(B), RK(C)

+R(A) := RK(B) % RK(C) +

+Performs modulus between RK(B) and RK(C) and holds the result into register R(A). +Both RK(B) and RK(C) may be either registers or constants. +

+

POW R(A), RK(B), RK(C)

+R(A) := RK(B) ^ RK(C) +

+Performs exponentiation between RK(B) and RK(C) and holds the result into register R(A). +Both RK(B) and RK(C) may be either registers or constants. +

+

UNM R(A), R(B)

+R(A) := -R(B) +

+Performs unary minus where register R(B) is negated and the value is placed in register R(A). +

+

NOT R(A), R(B)

+R(A) := not R(B) +

+Applies a boolean not to the value in register R(B) and holds the result in register R(A). +

+

LEN R(A), R(B)

+R(A) := length of R(B) +

+Returns the length of object in register R(B) and holds the result in register R(A). +

+

CONCAT R(A), R(B), R(C)

+R(A) := R(B).. ... ..R(C) +

+Performs the concatenation among two or more strings. The start register is R(B) and the +final register is R(C), meaning that R(C) should always be greater then R(B). +The result is stored in register R(A). +

+

JMP A, sBx

+pc+=sBx; if (A) close all upvalues >= R(A) + 1 +

+Performs a jump to sBx, which should be an instruction number or a label that should jump to. +If A is true then all upvalues up to R(A) + 1 are closed. +

+

EQ A, RK(B), RK(C)

+if ((RK(B) == RK(C)) ~= A) then pc++ +

+Performs a equality test between RK(B) and RK(C), wich may be registers or constants. +If the boolean is not A then next instruction is skipped. +

+

LT A, RK(B), RK(C)

+if ((RK(B) < RK(C)) ~= A) then pc++ +

+Performs a less than test between RK(B) and RK(C), wich may be registers or constants. +If the boolean is not A then next instruction is skipped. +

+

LE A, RK(B), RK(C)

+if ((RK(B) <= RK(C)) ~= A) then pc++ +

+Performs a less than or equal to test between RK(B) and RK(C), wich may be registers or constants. +If the boolean is not A then next instruction is skipped. +

+

TEST R(A), C

+if not (R(A) <=> C) then pc++ +

+Can be used to implement and/or logical operators, or for testing +a single register in a conditional statement. +TEST should be used when an assignment operation is not needed and works same way as TESTSET. +For more details, please, look at TESTSET. +

+

TESTSET R(A), R(B), C

+if (R(B) <=> C) then R(A) := R(B) else pc++ +

+Also can be used to implement and/or logical operators, or for testing +a single register in a conditional statement. +Register R(B) is coerced into a boolean and compared to the boolean field C. +If R(B) matches C then next instruction is skipped, otherwise R(B) is assigned to R(A). +

+

CALL R(A), B, C

+R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) +

+Performs a function call. R(A) holds the reference to the function object to be called. +Parameters to the function should be placed in the registers following R(A). +

+If B is 1 the function has no parameters. If B is 2 or more there are B-1 parameters. +If B is 0 the function parameters range from R(A+1) to the top of the stack. +

+Results returned by the function call are placed in a range of registers starting from R(A). +If C is 1 no return results. If C is 2 or more there will be C-1 results saved. +If C is 0 then multiple return results are saved. +

+

TAILCALL R(A), B, C

+return R(A)(R(A+1), ... ,R(A+B-1)) +

+Performs a tail call which happens when a return statement has a single function call as the expression. +Exactly like CALL, register R(A) is the reference to the function object to be called, +while B encodes the number of paramenters. However, even tough C is not used by TAILCALL, 0 should be +used to denote multiple return results. +

+

RETURN R(A), B

+return R(A), ... ,R(A+B-2) +

+Returns to the calling function with options return values. +

+If B is 1 there are no return values. If B is 2 or more, there are B-1 return values. +If B is 0 the set of values from R(A) to the top of the stack is returned. +

+

FORLOOP R(A) sBx

+R(A)+=R(A+2) ; if R(A) <?= R(A+1) then pc+=sBx; R(A+3)=R(A) +

+Should be used to perform an iteration of a numeric for loop. +A numeric for loop requires 4 registers on the stack where R(A) hold the initial value, +R(A+1) is the limit, R(A+2) is the stepping value and R(A+3) is the actual loop variable +that is local to the for block. +The argument sBx should be an instruction number or a label that should jump unconditionally to. +

+

FORPREP R(A), sBx

+R(A)-=R(A+2); pc+=sBx +

+Should be used to initialize a numeric for loop. +The argument sBx should be an instruction number or a label that should jump back to the loop body. +

+

TFORCALL R(A), C

+R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)) +

+Should be used to initialize a generic for loop, where +R(A) is the iterator function, R(A+1) is the state and R(A+2) is the enumeration index. +The loop variables are specified at locations R(A+3) and their count is defined by operand C, +which should be at least 1. +

+

TFORLOOP R(A), sBx

+if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } +

+Should be used to perform an iteration of a generic for loop. +If register R(A+1) is not nil then it is stored in R(A) and jump back to sBx. +The argument sBx should be an instruction number or a label that should jump to. +

+

SETLIST R(A), B, C

+R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B +

+Sets the values for a range of arrays elements in a table referenced by R(A), +argument B is the number of elements to set and argument C is the number of blocks +to be initialized. +If B is zero then B is the top. If C is zero then next instruction should be +EXTRAARG(real C). +

+

CLOSURE R(A), KPROTO(Bx)

+R(A) := closure(KPROTO[Bx]) +

+Should be used to create an instance of a closure of a function where KPROTO[Bx] is the +function name and R(A) is the register that assigns the reference to the instantiated +function object. +

+

VARARG R(A), B

+R(A), R(A+1), ..., R(A+B-2) = vararg +

+Copies B-2 parameters into a number of registers starting from R(A). +If B is 0, VARARG copies as many values as it can based on the number of parameters passed. +If a fixed number of values is required, B is a value greater than 1. +If any number of values is required then B is 0. +

+

EXTRAARG Ax

+

+Sets an extra larger argument for previous opcode. +If previous opcode is LOADKX then Ax might be any constant, but +if previous opcode is SETLIST then Ax must be an integer. +

+ +
+ +

Notes

+

+The current version of Lua Assembler/Disassembler is 0.2. +

+
+ +

Licence

+

+Copyright © 2012 Andre Murbach Maidl. +

+

+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +

+

+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +

+

+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +

+ +
+ +
+ + diff --git a/5.2/ladconf.lua b/5.2/ladconf.lua new file mode 100644 index 0000000..0a923a8 --- /dev/null +++ b/5.2/ladconf.lua @@ -0,0 +1,230 @@ +local OPCODE = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", + "GETUPVAL", "GETTABUP", "GETTABLE", "SETTABUP", + "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", + "ADD", "SUB", "MUL", "DIV", "MOD", "POW", + "UNM", "NOT", "LEN", "CONCAT", "JMP", + "EQ", "LT", "LE", "TEST", "TESTSET", + "CALL", "TAILCALL", "RETURN", "FORLOOP", + "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", + "CLOSURE", "VARARG", "EXTRAARG" } + +local LUA_ENV = "_ENV" +local LUA_SOURCE = "@Lua Assembler/Disassembler" + +local LUA_SIGNATURE = "\27Lua" +local LUAC_TAIL = "\x19\x93\r\n\x1a\n" +local LUAC_HEADERSIZE = string.len(LUA_SIGNATURE) + 2 + 6 + string.len(LUAC_TAIL) +local LUA_VERSION = 82 +local LUA_FORMAT = 0 + +local ENDIANNESS = 1 +local INT = 4 +local SIZE_T = 8 +local INSTRUCTION = 4 +local LUA_NUMBER = 8 +local INTEGRAL = 0 + +local LUA_TNIL = 0 +local LUA_TBOOLEAN = 1 +local LUA_TNUMBER = 3 +local LUA_TSTRING = 4 + +local iABC = 0 +local iABx = 1 +local iAsBx = 2 +local iAx = 3 + +local SIZE_C = 9 +local SIZE_B = 9 +local SIZE_Bx = (SIZE_C + SIZE_B) +local SIZE_A = 8 +local SIZE_Ax = (SIZE_C + SIZE_B + SIZE_A) + +local SIZE_OP = 6 + +local POS_OP = 0 +local POS_A = (POS_OP + SIZE_OP) +local POS_C = (POS_A + SIZE_A) +local POS_B = (POS_C + SIZE_C) +local POS_Bx = POS_C +local POS_Ax = POS_A + +local MASK_OP = math.ldexp(1, SIZE_OP) +local MASK_A = math.ldexp(1, SIZE_A) +local MASK_B = math.ldexp(1, SIZE_B) +local MASK_C = math.ldexp(1, SIZE_C) +local MASK_Bx = math.ldexp(1, SIZE_Bx) +local MASK_Ax = math.ldexp(1, SIZE_Ax) + +local ABC = { SIZE_OP, SIZE_A, SIZE_C, SIZE_B } + +local INT_MAX = (2 ^ ((SIZE_T * INT) - 1)) - 1 +local LUAI_BITSINT +if INT_MAX-20 < 32760 then + LUAI_BITSINT = 16 +elseif INT_MAX > 2147483640 then + LUAI_BITSINT = 32 +else + error ("you must define LUAI_BITSINT with number of bits in an integer") +end + +local MAX_INT = INT_MAX - 2 + +local MAXARG_Bx, MAXARG_sBx, MAXARG_Ax + +if SIZE_Bx < LUAI_BITSINT-1 then + MAXARG_Bx = bit32.lshift(1,SIZE_Bx)-1 + MAXARG_sBx = bit32.rshift(MAXARG_Bx,1) +else + MAXARG_Bx = MAX_INT + MAXARG_sBx = MAX_INT +end + +if SIZE_Ax < LUAI_BITSINT-1 then + MAXARG_Ax = bit32.lshift(1,SIZE_Ax)-1 +else + MAXARG_Ax = MAX_INT +end + +local MAXARG_A = bit32.lshift(1,SIZE_A)-1 +local MAXARG_B = bit32.lshift(1,SIZE_B)-1 +local MAXARG_C = bit32.lshift(1,SIZE_C)-1 + +local BITRK = bit32.lshift(1, (SIZE_B - 1)) + +local function ISK(x) + return bit32.btest(bit32.band(x, BITRK)) +end + +local function INDEXK(r) + return bit32.band(r, bit32.bnot(BITRK)) +end + +local MAXINDEXRK = BITRK - 1 + +local function RKASK(x) + return bit32.bor(x, BITRK) +end + +local function get_bit(x,a,b) + return (math.floor((x / 2^a) % 2^b)) +end + +local OpArgN = 0 +local OpArgU = 1 +local OpArgR = 2 +local OpArgK = 3 + +local opmodes = { + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iABC }, -- MOVE + { T = 0, A = 1, B = OpArgK, C = OpArgN, mode = iABx }, -- OP_LOADK + { T = 0, A = 1, B = OpArgN, C = OpArgN, mode = iABx }, -- OP_LOADKX + { T = 0, A = 1, B = OpArgU, C = OpArgU, mode = iABC }, -- OP_LOADBOOL + { T = 0, A = 1, B = OpArgU, C = OpArgN, mode = iABC }, -- OP_LOADNIL + { T = 0, A = 1, B = OpArgU, C = OpArgN, mode = iABC }, -- OP_GETUPVAL + { T = 0, A = 1, B = OpArgU, C = OpArgK, mode = iABC }, -- OP_GETTABUP + { T = 0, A = 1, B = OpArgR, C = OpArgK, mode = iABC }, -- OP_GETTABLE + { T = 0, A = 0, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_SETTABUP + { T = 0, A = 0, B = OpArgU, C = OpArgN, mode = iABC }, -- OP_SETUPVAL + { T = 0, A = 0, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_SETTABLE + { T = 0, A = 1, B = OpArgU, C = OpArgU, mode = iABC }, -- OP_NEWTABLE + { T = 0, A = 1, B = OpArgR, C = OpArgK, mode = iABC }, -- OP_SELF + { T = 0, A = 1, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_ADD + { T = 0, A = 1, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_SUB + { T = 0, A = 1, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_MUL + { T = 0, A = 1, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_DIV + { T = 0, A = 1, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_MOD + { T = 0, A = 1, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_POW + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iABC }, -- OP_UNM + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iABC }, -- OP_NOT + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iABC }, -- OP_LEN + { T = 0, A = 1, B = OpArgR, C = OpArgR, mode = iABC }, -- OP_CONCAT + { T = 0, A = 0, B = OpArgR, C = OpArgN, mode = iAsBx }, -- OP_JMP + { T = 1, A = 0, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_EQ + { T = 1, A = 0, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_LT + { T = 1, A = 0, B = OpArgK, C = OpArgK, mode = iABC }, -- OP_LE + { T = 1, A = 0, B = OpArgN, C = OpArgU, mode = iABC }, -- OP_TEST + { T = 1, A = 1, B = OpArgR, C = OpArgU, mode = iABC }, -- OP_TESTSET + { T = 0, A = 1, B = OpArgU, C = OpArgU, mode = iABC }, -- OP_CALL + { T = 0, A = 1, B = OpArgU, C = OpArgU, mode = iABC }, -- OP_TAILCALL + { T = 0, A = 0, B = OpArgU, C = OpArgN, mode = iABC }, -- OP_RETURN + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iAsBx }, -- OP_FORLOOP + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iAsBx }, -- OP_FORPREP + { T = 0, A = 0, B = OpArgN, C = OpArgU, mode = iABC }, -- OP_TFORCALL + { T = 0, A = 1, B = OpArgR, C = OpArgN, mode = iAsBx }, -- OP_TFORLOOP + { T = 0, A = 0, B = OpArgU, C = OpArgU, mode = iABC }, -- OP_SETLIST + { T = 0, A = 1, B = OpArgU, C = OpArgN, mode = iABx }, -- OP_CLOSURE + { T = 0, A = 1, B = OpArgU, C = OpArgN, mode = iABC }, -- OP_VARARG + { T = 0, A = 0, B = OpArgU, C = OpArgU, mode = iAx }, -- OP_EXTRAARG +} + +local function get_op_mode(o) + return opmodes[o].mode +end + +local ladconf = { + OPCODE = OPCODE, + LUA_ENV = LUA_ENV, + LUA_SOURCE = LUA_SOURCE, + LUA_SIGNATURE = LUA_SIGNATURE, + LUAC_TAIL = LUAC_TAIL, + LUAC_HEADERSIZE = LUAC_HEADERSIZE, + LUA_VERSION = LUA_VERSION, + LUA_FORMAT = LUA_FORMAT, + ENDIANNESS = ENDIANNESS, + INT = INT, + SIZE_T = SIZE_T, + INSTRUCTION = INSTRUCTION, + LUA_NUMBER = LUA_NUMBER, + INTEGRAL = INTEGRAL, + LUA_TNIL = LUA_TNIL, + LUA_TBOOLEAN = LUA_TBOOLEAN, + LUA_TNUMBER = LUA_TNUMBER, + LUA_TSTRING = LUA_TSTRING, + iABC = iABC, + iABx = iABx, + iAsBx = iAsBx, + iAx = iAx, + SIZE_C = SIZE_C, + SIZE_B = SIZE_B, + SIZE_Bx = SIZE_Bx, + SIZE_A = SIZE_A, + SIZE_Ax = SIZE_Ax, + SIZE_OP = SIZE_OP, + POS_OP = POS_OP, + POS_A = POS_A, + POS_C = POS_C, + POS_B = POS_B, + POS_Bx = POS_Bx, + POS_Ax = POS_Ax, + MASK_OP = MASK_OP, + MASK_A = MASK_A, + MASK_B = MASK_B, + MASK_C = MASK_C, + MASK_Bx = MASK_Bx, + MASK_Ax = MASK_Ax, + ABC = ABC, + INT_MAX = INT_MAX, + LUAI_BITSINT = LUAI_BITSINT, + MAX_INT = MAX_INT, + MAXARG_Bx = MAXARG_Bx, + MAXARG_sBx = MAXARG_sBx, + MAXARG_Ax = MAXARG_Ax, + MAXARG_A = MAXARG_A, + MAXARG_B = MAXARG_B, + MAXARG_C = MAXARG_C, + BITRK = BITRK, + ISK = ISK, + INDEXK = INDEXK, + MAXINDEXRK = MAXINDEXRK, + RKASK = RKASK, + get_bit = get_bit, + OpArgN = OpArgN, + OpArgU = OpArgU, + OpArgR = OpArgR, + OpArgK = OpArgK, + opmodes = opmodes, + get_op_mode = get_op_mode, +} + +return ladconf diff --git a/5.2/luaa.lua b/5.2/luaa.lua new file mode 100755 index 0000000..37e20fb --- /dev/null +++ b/5.2/luaa.lua @@ -0,0 +1,72 @@ +#!/usr/bin/env lua + +--[[ +Lua Assembler for Lua 5.2.0 +Version 0.2 +Author: Andre Murbach Maidl +]] + +INPUT = "luad.asm" +OUTPUT = "luaa.out" +DEBUG = false + +USAGE = [[ +usage: %s [options] [filename] +Available options are: +-h print this help +-o name output to file name (default is %s) +]] + +function usage(msg) + if msg ~= nil then + io.write(string.format("%s: %s\n", arg[0], msg)) + end + io.write(string.format(USAGE, arg[0], OUTPUT)) + os.exit(1) +end + +function doargs() + local i = 1 + while i <= #arg do + if string.find(arg[i], "^-") == nil then + INPUT = arg[i] + break + elseif arg[i] == "-h" then usage() + elseif arg[i] == "-o" then i = i + 1 + if arg[i] == nil then usage("'-o' needs argument") else OUTPUT = arg[i] end + else usage(string.format("'%s' unkown option", arg[i])) + end + i = i + 1 + end +end + +function read_input(filename) + local input = assert(io.open(filename, "r")) + local contents = input:read("*a") + input:close() + return contents +end + +if #arg < 1 then + usage ("no input file given") +end + +doargs() + +local assembler = require("assembler") +local contents = read_input(INPUT) +local ast = assembler.parse(contents) + +if not ast then + print ("syntax error") + os.exit (1) +end + +if DEBUG then assembler.print_ast(ast) end +local parsed = assembler.traverse(ast) +if parsed == nil then + error ("could not generate bytecode") +end +assembler.write(OUTPUT, parsed) + +os.exit(0) diff --git a/5.2/luad.lua b/5.2/luad.lua new file mode 100755 index 0000000..91f40cd --- /dev/null +++ b/5.2/luad.lua @@ -0,0 +1,62 @@ +#!/usr/bin/env lua + +--[[ +Lua Disassembler for Lua 5.2.0 +Version 0.2 +Author: Andre Murbach Maidl +]] + +INPUT = "luac.out" +OUTPUT = "luad.asm" +LISTING = 0 +DUMPING = true + +USAGE = [[ +usage: %s [options] [filename] +Available options are: +-h print this help +-l list on luac style (use -l -l for full listing) +-o name output to file name (default is %s) +-p parse only +]] + +function usage(msg) + if msg ~= nil then + io.write(string.format("%s: %s\n", arg[0], msg)) + end + io.write(string.format(USAGE, arg[0], OUTPUT)) + os.exit(1) +end + +function doargs() + local i = 1 + while i <= #arg do + if string.find(arg[i], "^-") == nil then + INPUT = arg[i] + break + elseif arg[i] == "-h" then usage() + elseif arg[i] == "-l" then LISTING = LISTING + 1 + elseif arg[i] == "-o" then i = i + 1 + if arg[i] == nil then usage("'-o' needs argument") else OUTPUT = arg[i] end + elseif arg[i] == "-p" then DUMPING = false + else usage(string.format("'%s' unkown option", arg[i])) + end + i = i + 1 + end +end + +if #arg < 1 then + usage ("no input file given") +end + +doargs() + +local chunk = assert(loadfile(INPUT)) +local bytecode = string.dump(chunk) +local disassembler = require("disassembler") + +local parsed = disassembler.parse(bytecode) +if LISTING > 0 then disassembler.print_function(parsed, LISTING > 1) end +if DUMPING then disassembler.write(OUTPUT, parsed) end + +os.exit(0)