对一个lua脚本文件,只有一条语句 print(“hello”, “world”),分别生成字节码文件如下:
32位字节码:
1b4c 4a02 022d 0200 0300 0300 0536 0000 0027 0101 0027 0202 0042 0003 014b 0001
000a 776f 726c 640a 6865 6c6c 6f0a 7072 696e 7400
64位字节码:
1b4c 4a02 0a2d 0200 0400 0300 0536 0000 0027 0201 0027 0302 0042 0003 014b 0001
000a 776f 726c 640a 6865 6c6c 6f0a 7072 696e 7400
上述红色字体表示的是有区别的地方,第一处是文件头部的flags标志,32位的是02,64位的是0a,有flags字段的定义:
#define BCDUMP_F_BE 0x01
#define BCDUMP_F_STRIP 0x02
#define BCDUMP_F_FFI 0x04
#define BCDUMP_F_FR2 0x08
可知,64位的BCDUMP_F_FR2为1,即可以从这个字段判断是32位还是64位字节码文件
第二处是原型头部的frame大小,32位是3,64位是4,即64位栈帧大小要比32位多1
第三处和第四处是指令的内容,栈帧变大后,同时指令中的索引也同时增大,对32位字节码反汇编内容如下:
0001 GGET 0 0 ; "print"
0002 KSTR 1 1 ; "hello"
0003 KSTR 2 2 ; "world"
0004 CALL 0 1 3
0005 RET0 0 1
64位字节码反汇编内容如下:
0001 GGET 0 0 ; "print"
0002 KSTR 2 1 ; "hello"
0003 KSTR 3 2 ; "world"
0004 CALL 0 1 3
0005 RET0 0 1
KSTR指令用于获取常量的内容,KSTR 2 1即将函数原型中常量索引为1的常量放入到栈中相对BASE偏移为2的内存处。Luajit中解释器的实现在对应的vm_<arch>.dasc文件中,这里以X86为例,即vm_x86.dasc文件,其中对KSTOR解释执行的代码如下:
case BC_KSTR:
| ins_AND // RA = dst, RD = str const (~)
| mov RD, [KBASE+RD*4]
| mov dword [BASE+RA*8+4], LJ_TSTR
| mov [BASE+RA*8], RD
| ins_next
break;
这里 RA为指令中的目标位置,即相对于即相对于BASE的位置 ,RD为常量的索引,先根据KBASE获取的常量的地址,再保存到RD中,接着把LJ_TSTR标志(字符串类型)和常量地址保存在了RA指定位置的栈中,然后执行下一条指令,可以看出栈中的每一个元素占8字节存储
接着看x64下的BC_KSTR解释:<