lua字节码的解析

时间:2022-10-25 17:09:34

lua的字节码

lua源码在执行前,会被编译为字节码,字节码能加快程序的加载,保存lua源码被意外的修复。lua的字节码只在具有相同的字长和字节顺序的机器上能够移植。
luac编译器能将lua源码编译为字节码二进制文件,其命令如:

luac a.lua

luac默认的输出文件为luac.out,可以通过 -o 选项来指定输出文件。

luac -o a.out a.lua

当Lua发布新版时,luac生成的二进制文件的内部格式可能改变。

字节码文件头

lua5.1字节码文件头的长度为12字节,在我的环境里(Win7 64位,VS下编译为Win32应用)如下:

1b4c 7561 5100 0104 0404 0800

其中第1-4字节为:"\033Lua";第5字节标识lua的版本号,lua5.1为 0x51;第6字节为官方中保留,lua5.1中为 0x0; 
第7字节标识字节序,little-endian为0x01,big-endian为0x00;
第8字节为sizeof(int);第9字节为sizeof(size_t);第10字节为sizeof(Instruction),Instruction为lua内的指令类型,在32位以上的机器上为unsigned int;第11字节为sizeof(lua_Number),lua_Number即为double;
第12字节是判断lua_Number类型起否有效,一般为 0x00;

lua5.2字节码文件头的长度为18字节,在我的环境里(Win7 64位,VS下编译为Win32应用)如下:

1b4c 7561 5200 0104 0404 0800 1993 0d0a 1a0a

其中第1-12字节与lua5.1意义相同,第5字节在lua5.2中为 0x52;
第13-18字节是为了捕获字节码的转换错误而设置的,其值为 "\x19\x93\r\n\x1a\n";

PS:lua在判断字节序时使用的方法如下:

1 void luaU_header (char* h)
2 {
3     int x=1;
4     //...
5     *h++=(char)*(char*)&x;             /* endianness */
6     //...
7 }

在little-endian时,*(char*)&x值为0x01;big-endian时,*(char*)&x值为 0x00;

字节码文件正文

lua5.1 在文件头之后,就是正头,它由一个个函数组成,其中第一个函数包含由文件内全部内容,引全局函数名为"@"+文件件名(包含".lua"后缀),在此文件中定义的函数都会在全局函数中以常量字符串保存;
每个函数的内容缓存如下:

源文件名的长度(包括'\0'),为sizeof(size_t)个字节长,只有全局函数有源文件名,其它内部函数其长度填0;
源文件名(包括\0),长度为长度*sizeof(char)个字节;
函数行数,全局函数的填0,长度为sizeof(int)个字节;
函数的最后一行,全局函数的填0,长度为sizeof(int)个字节;
函数的upvalues数目,长度为sizeof(char)个字节;
函数的参数个数,全局函数的填0,长度为sizeof(char)个字节;
函数的vararg个数,只有全局函数有;
函数最大的栈数目,长度为sizeof(char)个字节;
函数的指令数目,长度为sizeof(int)个字节;
函数的指令,长度为指令数目*sizeof(Instruction)个字节;
函数中常量的数目,长度为sizeof(int)个字节;
函数中的常量,长度为常量数目*(常量类似标识长度+指定常量点用的长度),常量类似标识长度为sizeof(char)个字节;
函数中的内部函数数目,长度为sizeof(int)个字节;
内部函数的定,格式同外部函数;
函数的调试信息;

文件binc.lua的内容如下:

1 local i = 6;
2 return 1;

其正文的字节码(lua5.1编译,不包括调试信息,前面的空白外为文件头):

                              0a00 0000
4062 696e 632e 6c75 6100 0000 0000 0000
0000 0000 0202 0400 0000 0100 0000 4140
0000 5e00 0001 1e00 8000 0200 0000 0300
0000 0000 0018 4003 0000 0000 0000 f03f
0000 0000

lua5.2 的正文部分与lua5.1存在差别。其没有源文件名的说明,别对于upvalue的处理也不一样,lua5.2中upvalue在常量后面定义,由upvalue的数目后加上分upvalue的定义组成。

明的了字节码的各部分组成之后,需要对其二进制数据做解析,现主要从指令、常量和upvalue部分来分析。
这部分内容留在下次继续。

 

个人博客:http://lontoken.com/