C GNU Lightning-类似Lisp的;套用;功能
我试图用GNU Lightning创建一个类似Lisp的“Apply”函数:一个函数F,它接收一个指向函数的指针、一个参数计数和一个整数数组,并使用正确数量的参数调用G 我的代码工作不正常。发生了什么?我该怎么办 代码如下:C GNU Lightning-类似Lisp的;套用;功能,c,compiler-construction,gnu,jit,jitter,C,Compiler Construction,Gnu,Jit,Jitter,我试图用GNU Lightning创建一个类似Lisp的“Apply”函数:一个函数F,它接收一个指向函数的指针、一个参数计数和一个整数数组,并使用正确数量的参数调用G 我的代码工作不正常。发生了什么?我该怎么办 代码如下: #include <stdio.h> #include <stdlib.h> #include <lightning.h> int f0() { printf("f0();\n"); } int f1(int p1) {
#include <stdio.h>
#include <stdlib.h>
#include <lightning.h>
int f0() {
printf("f0();\n");
}
int f1(int p1) {
printf("f1(%d);\n", p1);
}
int f2(int p1, int p2) {
printf("f2(%d, %d);\n", p1, p2);
}
int f3(int p1, int p2, int p3) {
printf("f3(%d, %d %d)\n", p1, p2, p3);
}
int main (int argc, char **argv) {
init_jit(argv[0]);
jit_state_t *_jit = jit_new_state();
int (*f)(int *g, int argc, int *argv);
jit_prolog();
jit_node_t *p_g = jit_arg();
jit_node_t *p_argc = jit_arg();
jit_node_t *p_argv = jit_arg();
jit_getarg(JIT_R0, p_g);
jit_getarg(JIT_R1, p_argc);
jit_getarg(JIT_R2, p_argv);
jit_prepare();
/* for ( ; argc; argc--, argv++) */
jit_node_t *label = jit_label();
jit_node_t *zero = jit_beqi(JIT_R1, 0);
// *argv
jit_ldr_i(JIT_V0, JIT_R2);
jit_pushargr(JIT_V0);
// Go next
// argv++
jit_addi(JIT_R2, JIT_R2, sizeof(int));
// argc--
jit_subi(JIT_R1, JIT_R1, 1);
//
jit_patch_at(jit_jmpi(), label);
jit_patch(zero);
jit_finishr(JIT_R0);
jit_reti(0);
jit_epilog();
f = jit_emit();
jit_clear_state();
f((void *)f0, 0, NULL);
int a1[] = {10};
f((void *)f1, 1, a1);
int a2[] = {100, 200};
f((void *)f2, 2, a2);
int a3[] = {1000, 2000, 3000};
f((void *)f3, 3, a3);
finish_jit();
return 0;
}
实际产出:
f0();
f1(10);
f2(200, 2);
f3(3000, 3 -13360)
如果我们在代码中添加对
jit\u反汇编()
的调用,我们会看到为f
函数生成的代码如下所示:
0x7f2511280000 sub $0x30,%rsp
0x7f2511280004 mov %rbx,0x28(%rsp)
0x7f2511280009 mov %rbp,(%rsp)
0x7f251128000d mov %rsp,%rbp
0x7f2511280010 sub $0x18,%rsp
0x7f2511280014 mov %rdi,%rax
0x7f2511280017 mov %rsi,%r10
0x7f251128001a mov %rdx,%r11
0x7f251128001d nopl (%rax)
0x7f2511280020 test %r10,%r10
0x7f2511280023 je 0x7f2511280040
0x7f2511280029 movslq (%r11),%rbx
0x7f251128002c mov %rbx,%rdi
0x7f251128002f add $0x4,%r11
0x7f2511280033 sub $0x1,%r10
0x7f2511280037 jmpq 0x7f2511280020
0x7f251128003c nopl 0x0(%rax)
0x7f2511280040 callq *%rax
0x7f2511280042 xor %rax,%rax
0x7f2511280045 mov %rbp,%rsp
0x7f2511280048 mov 0x28(%rsp),%rbx
0x7f251128004d mov (%rsp),%rbp
0x7f2511280051 add $0x30,%rsp
0x7f2511280055 retq
如果我们查看由jit\U pushargr生成的代码,问题就会变得很明显:
0x7f251128002c mov %rbx,%rdi
因此,这将*argv
的值设置为被调用函数的第一个参数(rdi
是保存x64调用约定中第一个参数的寄存器)。它多次这样做是因为它在一个循环中,但它总是被设置的第一个参数。因此,当在循环后调用函数时,rdi
将保存循环中最后写入它的值(即,argv
中的最后一个值),而其他参数寄存器/内存位置根本不会被写入
jit_pushargr
的工作方式是,当您第一次调用它时,它将写入第一个参数,当您第二次调用它时,它将写入第二个参数,依此类推。但是在你的代码中你只调用它一次,所以它只写第一个参数
因此,要使用lightning创建应用函数,需要实际调用jit\u pushargr
argc
次。这意味着,您不需要生成一个通用的apply函数,而是需要在普通的C语言中定义apply函数本身,并生成一个helper函数来推送给定数量的参数
或者,您可以完全不用lightning,而是使用libffi来实现这一点,这将是用于此类用途的更传统的工具,并且不会在每次调用
apply
时产生生成新代码的开销。当然,这不会阻止您使用lightning生成的代码调用apply
函数。非常感谢。目的是为内嵌APPLY代码的解释器创建JIT。这必须接受N个单参数,最后一个作为其他参数的列表…类似于此:int g(p1,p2,p3,p4,p5,p6,p7,p8){…}int数组[]={4,5,6,7};f(g,0,1,2,3,数组);参数的数量必须是任意的。@Tommy很抱歉,我不完全清楚您所说的“内联应用程序代码”是什么意思,或者您通常想要得到什么。我从您的第一句话中得到的是,您正在为您的语言编写一个JIT编译器,并且希望您的apply
函数能够从该语言中使用。然后,第二句话似乎是对apply
所做的事情的解释(在这一点上似乎是多余的)。我不明白的是你在问我什么(如果有的话)。@汤米,你让它工作了吗?如果你仍然被困住,我很乐意解释更多。很抱歉,我没有再回答你,但我放弃了这个想法。我还没有准备好改变解释器的架构
0x7f251128002c mov %rbx,%rdi