|
|
碰到一个麻烦的问题, 想要用setjmp/longjmp解决,问题是这两个函数不会保存堆栈,
只是保存修改寄存器,因此在从里向外longjmp是安全的,从外向里longjmp则局部变量
会出问题。
下面是一个示例代码,从main跳到f1,再跳回main,在这一跳中必须要先保存
堆栈否则f1的局部变量就会丢失,再跳到f1,再返回到main。
想要实现的效果是: 在第二次main跳到f1之后,对于f1来说,似乎就是从switch(setjmp...)
返回1开始执行, 但是下面的代码有问题,总是f1的局部变量b,c被setjmp的返回值和参数地址
所覆盖。
代码只能用gcc编译,因为使用的jmp_buf实现是gcc特有的, 我用的gcc3.3.5,setjmp/
longjmp的实现看了看glibc的i386/setjmp/longjmp代码,大概知道怎么回事。
另外restorestack是有问题的,可能缺页或者访问非法内存,不过我运行的时候倒没
出现这些问题。
- #include <stdio.h>
- #include <stdlib.h>
- #include <setjmp.h>
- /*
- # define JB_BX 0
- # define JB_SI 1
- # define JB_DI 2
- # define JB_BP 3
- # define JB_SP 4
- # define JB_PC 5
- */
- #define JMPBUF(buf, idx) (((int*)buf)[idx])
- #define BX(buf) JMPBUF(buf, 0)
- #define SI(buf) JMPBUF(buf, 1)
- #define DI(buf) JMPBUF(buf, 2)
- #define BP(buf) JMPBUF(buf, 3)
- #define SP(buf) JMPBUF(buf, 4)
- #define PC(buf) JMPBUF(buf, 5)
- #define savestack() if (NULL != sp1 && NULL != sp2) { \
- for (i=0; i < sp1 - sp2; ++i) { \
- stack[i] = *(sp2 + i); \
- } \
- } else abort();
- #define restorestack() if (NULL != sp1 && NULL != sp2) { \
- for (i=0; i < sp1 - sp2; ++i) { \
- *(sp2 + i) = stack[i]; \
- } \
- } else abort();
- jmp_buf buf1;
- jmp_buf buf2;
- int j1 = 1;
- int j2 = 1;
- int i = 0;
- int* sp1 = NULL;
- int* sp2 = NULL;
- int stack[1024];
- void output(jmp_buf buf) {
- int* p = (int*)buf;
- int i = 0;
- printf("BX=%u, SI=%u, DI=%u, BP=%u, SP=%u, PC=%u\n",
- p[0], p[1], p[2], p[3], p[4], p[5]);
- printf("stack from SP: ");
- for (i = 0; i < 30; ++i) {
- printf("%u ", *(int*)(p[4] + i));
- }
- printf("\n&output()=%u, p =%u, buf=%u\n", output, p, (int*)buf);
- }
- void f1() {
- int a = 6;
- int b = 7;
- int c = 8;
- printf("f1: enter: \t\ta=%x, b=%x, c=%x\n", a, b, c);
- switch (setjmp(buf2)) {
- case 0:
- sp2 = (int*)SP(buf2);
- printf("f1: case 0: \t\ta=%x, b=%x, c=%x\n", a, b, c);
- savestack();
- if (j1) longjmp(buf1, 1);
- printf("f1: case 0: after longjump\n");
- break;
- case 1:
- printf("f1: case 1: jump from main\n");
- printf("f1: \t\ta=%x, b=%x, c=%x\n", a, b, c);
- printf("&buf1=%x, &buf2=%x, &a=%x, &b=%x, c=%x\n", &buf1, &buf2,
- &a, &b, &c);
- break;
- }
- printf("f1: leave: \t\ta=%x, b=%x, c=%x\n", a, b, c);
- }
- int main(int argc, char** argv) {
- int x = 3;
- int y = 4;
- int z = 5;
- (void)argc;
- (void)argv;
- printf("main: enter: \t\tx=%x, y=%x, z=%x\n", x, y, z);
- switch (setjmp(buf1)) {
- case 0:
- sp1 = (int*)SP(buf1);
- printf("main: case 0: call f1(): \t\tx=%x, y=%x, z=%x\n", x, y, z);
- f1();
- printf("main: case 0: back from f1()\n");
- break;
- case 1:
- printf("main: case 1\n");
- {
- int aa[512];
- int i;
- for (i=0; i < 512; ++i) {
- aa[i] = 512 - i;
- }
- }
- printf("main: case 1: jump to f1(): \t\tx=%x, y=%x, z=%x\n", x, y, z);
- restorestack();
- if (j2) longjmp(buf2, 1);
- printf("main: case 1: back from f1()\n");
- break;
- }
- printf("main: leave: \t\tx=%x, y=%x, z=%x\n", x, y, z);
- return 0;
- }
复制代码 |
|