在上一篇文章中我们简单地介绍了一下GNU/Lightning,现在我们来讲解上一篇文章中测试用的示例。
#include <stdio.h>
#include <lightning.h>
static jit_state_t *_jit;
typedef int (*pifi)(int); /* Pointer to Int Function of Int */
int main(int argc, char *argv[])
{
jit_node_t *in;
pifi incr;
init_jit(argv[0]);
_jit = jit_new_state();
jit_prolog(); /* prolog */
in = jit_arg(); /* in = arg */
jit_getarg(JIT_R0, in); /* getarg R0 */
jit_addi(JIT_R0, JIT_R0, 1); /* addi R0, R0, 1 */
jit_retr(JIT_R0); /* retr R0 */
incr = jit_emit();
jit_clear_state();
/* call the generated code, passing 5 as an argument */
printf("%d + 1 = %d\n", 5, incr(5));
jit_destroy_state();
finish_jit();
return 0;
}
引入头文件
想要成功使用lightning中的一系列函数与变量,我们需要引入头文件lightning.h
。
声明jit_state_t
结构指针
static jit_state_t *_jit;
jit_state_t
结构用于存储jit代码声明信息,_jit
这个变量名在lightning中有特殊意义,所以通常情况下我们应该直接使用_jit
,或者用#define _jit <其它名称>
来定义。
定义一个函数类型
typedef int (*pifi)(int);
为了方便我们后续使用jit生成的函数,我们定义一个函数类型与之对应。该类型的函数接收一个int整型返回一个int整型。
声明一个变量用来获取函数参数
使用jit_node_t
声明的指针in
可以用于在jit代码中获取函数的变量。
声明函数指针变量
全局初始化jit
必须在创建jit_state_t
对象之前调用此函数。该函数会进行全局状态初始化,可能需要检测CPU或操作系统特性。如果在配置时启用了反汇编,它会接收一个字符串参数,该参数稍后用于使用GNU binutils从共享对象中读取符号。如果不执行反汇编,则可以使用NULL指针作为参数。
创建state
准备书写jit代码
在此函数调用后我们就可以开始书写jit代码了。
获取函数输入
in = jit_arg();
jit_getarg(JIT_R0, in);
使用in = jit_arg()
从函数中获取参数「这里说的函数当前还没有实现,等到相关的代码书写完后会将这个函数赋值给incr
」;调用jit_getarg
函数将得到的参数in
的值传递给寄存器JIT_R0
。
实现加一操作
jit_addi(JIT_R0, JIT_R0, 1);
jit_addi
可实现寄存器整数相加赋值的操作,将第2、3个参数的寄存器值或数值相加并赋值给第1个参数的寄存器。
返回寄存器的值
类似C程序中函数的返回语句return
,此处使用jit_retr
返回了寄存器JIT_R0
的值。
生成机器码
该函数会将之前书写的jit代码转换为机器码,然后封装成一个函数指针,我们使用incr
接收它。
清除state
得到incr
函数后我们清理掉state中的一些不必要的内容。
调用并观察incr
printf("%d + 1 = %d\n", 5, incr(5));
释放内存中的state信息
确定不会再使用jit生成的函数后,我们可以释放并销毁内存中的state信息。
结束jit
最后我们再清除全局的jit state信息。