Luajit 字节码分析之 KSTR
luajit的解析器是通过汇编代码实现的,代码晦涩难懂,但是我还是想尝试对一些OPCode进行解析,比如下面的lua代码:
通过下面的指令可以获得对应的opcode:
那么KSTR这个OPCode在Luajit里面的实现是怎样的呢?可以在vm_x64.dasc文件里面找到:
这几行汇编代码都分别代表什么意思,我们一个一个的来解析。
首先假设我们在执行第一个指令 :
那么RA=0,RD=0。
ins_AND宏定义
ins_AND宏的实现很简单,就是对RD取反,取反后RD=-1。
关于GCProto的内存布局
我们这里只列出了与KSTR指令相关的数据。MRef k指向的地址是存放全局常量的基地址。GCProto的内存布局如下:
那么在上面的汇编代码里面,KBASE就是global consts内存区域的高位地址。为何KBASE即为global consts的高位地址呢?
在执行BC_KSTR之前会先执行BC_IFUNCV,其中会计算KBASE的值,他的计算方法是[PC-4+PC2PROTO(k)]。PC2PROTO宏又是什么?
不难看出PC2PROTO(k)是计算GCproto->k到GCproto结构体尾部的字节长度,然后取负。PC寄存器存储的是当前OPCode运行的地址的后4字节,BC_IFUNCV又是第一个运行的OPCode,因此PC-4代表的意义就是GCProto结构体底部的绝对地址。因此可以想到PC-4+PC2PROTO(k)即为GCproto->k所在的地址。因此:
我们回来再看下面这条汇编指令:
因此,[KBASE+RD*8]计算的就是第一个常量字符串"123"的地址,即:
然后进行第二条汇编指令:
我个人感觉这种设计很巧妙。x64的线性地址48-63位是保留的,因此luajit利用这几位做类型信息的保存,settp是将LJ_TSTR左移47位,然后与RD做或运算。
最后一个汇编指令:
有了上面的基础,这个指令比较好理解了,它将RD的数据放到栈(BASE)的第一个位置上。
版权声明: 本文为 InfoQ 作者【whosemario】的原创文章。
原文链接:【http://xie.infoq.cn/article/b059976e8b02111dbae64b445】。文章转载请联系作者。
评论