2014-03-02 81 views
0

我想建立我自己的檢查點庫。我能夠將堆棧幀保存到調用checkpoint_here(堆棧指針)的文件中,並且可以通過調用recover(堆棧指針)函數稍後恢復。如何在gcc中恢復堆棧幀?

這是我的問題:我能夠從功能恢復(sp)跳轉到main(),但堆棧幀被改變(堆棧指針,幀指針)。所以我想在checkpoint_here(sp)之後立即從恢復(sp)跳轉到main,保留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(以恢復%rsp%rbp,x86-64)。你可以使用longjmp(見setjmp(3)longjmp(3)) - 由於longjmp正在恢復堆棧指針 - 假設你明白的實施細則。

堆棧有,由於ASLR,「隨機」,非重複性,地理位置優越。換句話說,如果您啓動兩次相同的程序,則main的堆棧指針將會不同。而在C中,一些堆棧幀包含一個指向其他堆棧幀的指針。另請參閱this answer

閱讀更多關於application checkpointing(見this)並研究源代碼(或使用)BLCR。您可能會限制使用的C代碼(例如,如果您生成C代碼),並且您可能會使用MELT來滿足您的需要,從而可能會擴展GCC。這是一項重要的工作。

BTW,MELT(內部也是)生成C++代碼,受限制堆棧幀可以很容易檢查點。你可以把它當作靈感來源。

閱讀也即將x86 calling conventionsgarbage collection(因爲精確的GC具有掃描本地指針,它類似於您的需求)。