Lua5.1字节码编译器生成无效字节码问题排查求助
Lua 5.1字节码生成失败问题排查
我有一份Lua 5.1 VM指令表,示例如下:
{ {op=5, A=0, Bx=1, const="Print"} -- 更多指令 }
尝试将这些指令转换为可在LBI(Lua Bytecode Interpreter)中运行的字节码,但生成的字节码无效,无法执行。以下是我的实现代码:
local function tenseRecompiler(instructions, constants) local header = string.char(0x1B, 0x4C, 0x75, 0x61, 0x51, 0x00, 0x01, 0x04, 0x04, 0x04, 0x08) local lua_opcode_types = { "ABC", "ABx", "ABC", "ABC", "ABC", "ABx", "ABC", "ABx", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "AsBx", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "ABC", "AsBx", "AsBx", "ABC", "ABC", "ABC", "ABx", "ABC", } local function encodeByte(value) return string.char(value) end local function encodeInt16(value) return string.char(value % 256) .. string.char(math.floor(value / 256) % 256) end local function encodeInt32(value) return string.char(value % 256) .. string.char(math.floor(value / 256) % 256) .. string.char(math.floor(value / 65536) % 256) .. string.char(math.floor(value / 16777216) % 256) end local bytecodeLines = {} local lineInfo = {} for i, v in pairs(instructions) do local op = v.op or -1 -- -1 is not a valid OPCODE, so it is an error local a = v.A or 0 local b = v.B or 0 local c = v.C or 0 local Bx = v.Bx or 0 local sBx = v.sBx or 0 if op == -1 then print("Invalid OPCODE") do return end end if lua_opcode_types[op] == "ABC" then --ABC bytecodeLines[#bytecodeLines + 1] = encodeByte(a) bytecodeLines[#bytecodeLines + 1] = encodeByte(b) bytecodeLines[#bytecodeLines + 1] = encodeByte(c) elseif lua_opcode_types[op] == "AsBx" then --AsBx bytecodeLines[#bytecodeLines + 1] = encodeByte(a) bytecodeLines[#bytecodeLines + 1] = encodeInt32(sBx) elseif lua_opcode_types[op] == "ABx" then --ABx bytecodeLines[#bytecodeLines + 1] = encodeByte(a) bytecodeLines[#bytecodeLines + 1] = encodeInt16(Bx) end lineInfo[#bytecodeLines + 1] = 1 end local constMap = {} local constCount = 0 for _, const in ipairs(constants) do constCount = constCount + 1 constMap[const] = constCount bytecodeLines[#bytecodeLines + 1] = encodeByte(0x1B) -- OP_CONSTANT bytecodeLines[#bytecodeLines + 1] = encodeByte(constCount) bytecodeLines[#bytecodeLines + 1] = const end local bytecode = table.concat(bytecodeLines) local bytecodeSize = #bytecode local constantCount = #constants local instructionCount = #instructions local lineInfoSize = #lineInfo * 4 -- Each line number is encoded as a 4-byte integer local sourceFileName = "@TENSE.lua" local sourceFileNameLength = #sourceFileName local sourceFileNameSize = sourceFileNameLength + 1 -- Include null terminator local bytecodeHeader = header .. string.char(0, 0, 0, 0, 0, 0, 0, 0) .. sourceFileName .. "@" .. string.char(0,0,0,0,0,0,0) .. "�" .. string.char(0, 0, 0, 0) local bytecodeFile = bytecodeHeader .. bytecode .. table.concat(lineInfo) io.open("luac1.out", "wb"):write(bytecodeFile) end
核心问题分析
1. 指令编码完全不符合Lua 5.1规范
Lua 5.1的每个指令是固定4字节小端整数,当前代码存在严重错误:
- ABC类型指令仅编码3字节(A/B/C各1字节),未存储opcode
- ABx类型编码1+2=3字节,AsBx类型编码1+4=5字节,破坏了4字节固定长度结构
- 正确做法:将opcode(6位)、A(8位)、B/C/Bx/sBx(18位)打包进一个4字节小端整数,示例:
local function encodeInstruction(op, a, b, c, bx, sbx) local code = op code = code + (a << 6) local fmt = lua_opcode_types[op+1] -- Lua opcode从0开始,数组索引从1开始 if fmt == "ABC" then code = code + (b << 14) code = code + (c << 23) elseif fmt == "ABx" then code = code + (bx << 14) elseif fmt == "AsBx" then code = code + ((sbx + 131071) << 14) -- sBx是有符号数,需偏移为无符号 end return encodeInt32(code) -- 小端编码4字节 end
2. 常量池处理逻辑错误
当前代码把常量以OP_CONSTANT指令的形式插入字节码,完全错误:
- Lua字节码的常量池是独立于指令的结构,存放在头部之后、指令之前
- 每个常量需要按类型(字符串、数字、布尔等)编码,字符串需先存长度再存内容(带null终止)
- 正确流程:先编码常量池的大小,再逐个编码每个常量的类型和数据,指令中的Bx/sBx引用常量池的索引
3. 字节码头部构造混乱
当前头部拼接了大量无意义字符,不符合Lua 5.1字节码文件结构。正确的头部结构为:
- 签名:
0x1B 0x4C 0x75 0x61(\x1BLua) - 版本号:
0x51(对应Lua 5.1) - 格式号:
0x00 - 大小端标识:
0x01(小端) - 数据类型大小:int(4)、size_t(4)、instruction(4)、number(8)
- 源文件名长度(size_t)、源文件名(带null终止)
- 常量池大小(int)、常量池内容
- 指令数(int)、指令内容
- 行号表大小(int)、行号表内容(每个行号是int)
- 局部变量表大小(int)、局部变量表内容
- Upvalue表大小(int)、Upvalue表内容
4. Opcode索引不匹配
Lua 5.1的opcode范围是0~34(共35个),但当前lua_opcode_types数组长度为38,且索引从1开始,而opcode从0开始,会导致类型判断错误。需修正数组长度为35,并确保用op+1索引对应正确格式。
5. 行号表编码错误
当前lineInfo直接存储数字1,未编码为4字节整数,且拼接位置错误。正确做法是将每个行号用encodeInt32编码后,放在指令之后、局部变量表之前,同时头部要正确声明行号表的大小。
内容的提问来源于stack exchange,提问作者cheatcentral
相关产品推荐
相关产品推荐

