在了解lightning的基本使用方式后,我们再来了解如何在lightning中调用c函数。
我们以调用c程序中的printf
函数为例,这里先列出完整代码:
#include <stdio.h>
#include <lightning.h>
static jit_state_t *_jit;
typedef void (*pvfi)(int); /* Pointer to Void Function of Int */
int main(int argc, char *argv[]) {
pvfi myFunction; /* ptr to generated code */
jit_node_t *start, *end; /* a couple of labels */
jit_node_t *in; /* to get the argument */
init_jit(argv[0]);
_jit = jit_new_state();
start = jit_note(__FILE__, __LINE__);
jit_prolog();
in = jit_arg();
jit_getarg(JIT_R1, in);
jit_prepare();
jit_pushargi((jit_word_t)"generated %d bytes\n");
jit_ellipsis();
jit_pushargr(JIT_R1);
jit_finishi(printf);
jit_ret();
jit_epilog();
end = jit_note(__FILE__, __LINE__);
myFunction = jit_emit();
/* call the generated code, passing its size as argument */
myFunction((char*)jit_address(end) - (char*)jit_address(start));
jit_clear_state();
jit_disassemble();
jit_destroy_state();
finish_jit();
return 0;
}
标记注释
start = jit_note(__FILE__, __LINE__);
/* ... ... */
end = jit_note(__FILE__, __LINE__);
这两条指令调用了jit_note
宏,它在jit
代码中创建了一个注释;jit_note
的参数通常是文件名字符串和行号整数,但如果只需要在代码中创建一个简单的标记,则使用NULL
作为字符串参数是完全有效的。
处理可变参量
由于函数printf
是个可变参函数,所以需要调用jit_ellipsis()
。
字符串参数处理
jit_pushargi((jit_word_t)"generated %d bytes\n");
使用jit_word_t
做字符串参数的类型转换。
引入并调用c函数
jit_prepare();
/* ... ...*/
jit_finishi(printf);
在jit中调用printf
函数,需要在装填参数前先执行jit_prepare()
函数,在完成参数装填后需要执行jit_finishi(printf)
。
显式的写入结语
lightning可以自己处理代码段截止内容,但是有的时候为了能准确的标记代码段的地址需要我们调用jit_epilog()
来显式的处理。
通过调用函数执行jit代码
myFunction((char*)jit_address(end) - (char*)jit_address(start));
jit_clear_state();
调用jit_address
获取字节地址需要使用到jit state中的信息,因此应当放在jit_clear_state()
前执行。
标准输出
disassemble
会将生成的代码转储到标准输出,除非lightning是在禁用反汇编程序的情况下构建的,在这种情况下不会显示任何输出。