我想建立自己的检查点库。我能够将堆栈帧保存到调用checkpoint_here(堆栈指针)的文件中,以后可以通过调用recover(堆栈指针)函数来恢复。
这是我的问题:我能够从函数recover(sp)跳转到main()但是堆栈帧被更改(堆栈指针,帧指针)。所以我想在checkpoint_here(sp)调用后保留main()的堆栈帧,然后从recover(sp)跳转到main。我已经尝试过setjmp / longjmp,但无法让它们正常工作。谢谢你的预期。
//jmp_buf env;
void *get_pc () { return __builtin_return_address(1); }
void checkpoint_here(register int *sp){
//printf("%p\n",get_pc());
void *pc;
pc=get_pc();//getting the program counter of caller
//printf("pc inside chk:%p\n",pc);
size_t i;
long size;
//if(!setjmp(env)){
void *l=__builtin_frame_address(1);//frame pointer of caller
int fd=open("ckpt1.bin", O_WRONLY|O_CREAT,S_IWUSR|S_IRUSR|S_IRGRP);
int mfd=open("map.bin", O_WRONLY|O_CREAT,S_IWUSR|S_IRUSR|S_IRGRP);
size=(long)l-(long)sp;
//printf("s->%ld\n",size);
write(mfd,&size,sizeof(long)); //writing the size of the data to be written to file.
write(mfd,&pc,sizeof(long)); //writing program counter of the caller.
write(fd,(char *)sp,(long)l-(long)sp); //writing local variables on the stack frame of caller.
close(fd);
close(mfd);
//}
}
void recover(register int *sp){
//int dummy;
long size;
void *pc;
//printf("old %p\n",sp);
/*void *newsp=(void *)&dummy;
printf("new %p old %p\n",newsp,sp);
if(newsp>=(void *)sp)
recover(sp);*/
int fd=open("ckpt1.bin", O_RDONLY,0644);
int mfd=open("map.bin", O_RDONLY,0644);
read(mfd,&size,sizeof(long)); //reading size of data written
read(mfd,&pc,sizeof(long)); //reading program counter
read(fd,(char *)sp,size); //reading local variables
close(mfd);
close(fd);
//printf("got->%ld\n",size);
//longjmp(env,1);
void (*foo)(void) =pc;
foo(); //trying to jump to main just after checkpoint_here() is called.
//asm volatile("jmp %0" : : "r" (pc));
}
int main(int argc,char **argv)
{
register int *sp asm ("rsp");
if(argc==2){
if(strcmp(argv[1],"recover")==0){
recover(sp); //restoring local variables
exit(0);
}
}
int a, b, c;
float s, area;
char x='a';
printf("Enter the sides of triangle\n");
//printf("\na->%p b->%p c->%p s->%p area->%p\n",&a,&b,&c,&s,&area);
scanf("%d %d %d",&a,&b,&c);
s = (a+b+c)/2.0;
//printf("%p\n",get_pc());
checkpoint_here(sp); //saving stack
//printf("here\n");
//printf("nsp->%p\n",sp);
area = (s*(s-a)*(s-b)*(s-c));
printf("%d %d %d %f %f %d\n",a,b,c,s,area,x);
printf("Area of triangle = %f\n", area);
printf("%f\n",s);
return 0;
}
答案 0 :(得分:0)
一般情况下你不能这样做。
您可以尝试使用不可移植extended asm
instructions(恢复x86-64上的%rsp
和%rbp
)。您可以使用longjmp(请参阅setjmp(3)和longjmp(3)) - 因为longjmp
正在恢复堆栈指针 - 假设您了解实现细节。
由于ASLR,堆栈具有"随机",不可重现的位置。换句话说,如果你开始两次相同的程序,main
的堆栈指针将是不同的。在C中,一些堆栈帧包含指向其他堆栈帧的指针。另请参阅this answer。
详细了解application checkpointing(请参阅this)并研究源代码(或使用)BLCR。
您可能限制使用C代码(例如,如果您生成C代码),您可能会根据需要使用MELT扩展GCC。这是一项重要的工作。
BTW,MELT(内部也)生成C ++代码,受限堆栈帧,可以轻松检查。您可以将其作为灵感来源。
另请阅读x86 calling conventions和garbage collection(因为精确的GC必须扫描本地指针,这与您的需求类似)。