1

独自のチェックポイント ライブラリを構築したい。スタック フレームを checkpoint_here(stack pointer) を呼び出してファイルに保存することができ、recover(stack pointer) 関数を呼び出して後で復元できます。

ここに私の問題があります:関数recover(sp)からmain()にジャンプできますが、スタックフレームが変更されます(スタックポインター、フレームポインター)。そこで、main() のスタック フレームを保持したまま checkpoint_here(sp) を呼び出した直後に、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;
}
4

1 に答える 1

1

一般的にはできません。

移植性のない拡張asm命令を試すことができます ( x86-64%rspを復元するため%rbp) 。longjmpを使用できます( setjmp(3)およびlongjmp(3 ) を参照) -スタック ポインターを復元するため - 実装の詳細を理解していることを前提としています。longjmp

ASLRのおかげで、スタックには「ランダムな」再現不可能な場所があります。つまり、同じプログラムを 2 回起動すると、スタック ポインタmainが異なります。また、C では、一部のスタック フレームに他のスタック フレームへのポインタが含まれています。この回答も参照してください。

アプリケーション チェックポインティングの詳細を読み(これを参照)、ソース コードを調べます (またはBLCRを使用します) 。

おそらく、使用する C コードを制限することができ (たとえば、C コードを生成する場合)、必要に応じてMELTを使用して GCC を拡張することができます。これはかなりの量の作業です。

ところで、MELT は (内部的にも) C++ コードを生成しており、スタック フレームが制限されているため、簡単にチェックポイントを設定できます。それをインスピレーションの源として捉えることができます。

x86 呼び出し規則ガベージ コレクションについてもお読みください(正確な GC はローカル ポインターをスキャンする必要があるため、これはニーズに似ています)。

于 2014-03-02T07:59:15.927 に答える