简体   繁体   English

如何在gcc中还原堆栈帧?

[英]How to restore stack frame in gcc?

I want to build my own checkpoint library. 我想建立自己的检查点库。 I'm able to save the stack frame to a file calling checkpoint_here(stack pointer) and that can be restored later via calling recover(stack pointer) function. 我能够将堆栈帧保存到调用checkpoint_here(stackpointer)的文件中,以后可以通过调用recover(stackpointer)函数来还原该文件。

Here is my problem: I'm able to jump from function recover(sp) to main() but the stack frame gets changed(stack pointer,frame pointer). 这是我的问题: 我可以从功能restore(sp)跳转到main(),但是堆栈框架被更改了(堆栈指针,框架指针)。 So I want to jump to main from recover(sp) just after is checkpoint_here(sp) called retaining the stack frame of main(). 所以我想在checkpoint_here(sp)被称为保留main()的堆栈帧之后,从restore(sp)跳转到main。 I've tried setjmp/longjmp but can't make them working.Thanks in anticipation. 我已经尝试过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;
}

You cannot do that in general. 通常,您不能这样做。

You might try non-portable extended asm instructions (to restore %rsp and %rbp on x86-64 ). 您可以尝试非便携式扩展asm指令 (以在x86-64上还原%rsp%rbp )。 You could use longjmp (see setjmp(3) and longjmp(3) ) -since longjmp is restoring the stack pointer- assuming you understand the implementation details. 您可以使用longjmp (请参阅setjmp(3)longjmp(3) )-因为longjmp正在还原堆栈指针-假设您了解实现细节。

The stack has, thanks to ASLR , a "random", non reproducible, location. 由于使用了ASLR ,该堆栈具有“随机”的,不可复制的位置。 In other words, if you start twice the same program, the stack pointer of main would be different. 换句话说,如果您两次启动同一程序,则main的堆栈指针将不同。 And in C some stack frames contain a pointer into other stack frames. 在C语言中,某些堆栈帧包含指向其他堆栈帧的指针。 See also this answer . 另请参阅此答案

Read more about application checkpointing (see this ) and study the source code (or use) BLCR . 了解更多关于应用程序检查点 (见 ),并研究源代码(或使用) BLCR

You could perhaps restrict the C code to be used (eg if you generate the C code) and you might perhaps extend GCC using MELT for your needs. 您可能会限制使用C代码(例如,如果生成C代码),并且可能会根据需要使用MELT扩展GCC。 This is a significant amount of work. 这是大量的工作。

BTW, MELT is (internally also) generating C++ code, with restricted stack frames which could be easily checkpointable. 顺便说一句,MELT(也在内部)生成C ++代码,其堆栈框架有限 ,可以很容易地进行检查。 You could take that as an inspiration source. 您可以将其作为灵感来源。

Read also about x86 calling conventions and garbage collection (since a precise GC has to scan local pointers, which is similar to your needs). 另请阅读有关x86调用约定垃圾回收的信息 (因为精确的GC必须扫描本地指针,这与您的需求类似)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM