分类: C/C++
2013-06-03 10:23:53
原文地址:setjmp和longjmp的实现原理 作者:CUDev
#include #include #include static jmp_buf jmpbuf_1; int g_a = 0; void test(int index, int *local_val) { g_a = 1111; *local_val = 2222; longjmp(jmpbuf_1,index); } int main(int argc, char *argv[]) { int ret = 0, index = 0; int l_a=1; if(argc!=2) index = 1; else { index = atoi(argv[1]); if(index==0 || index>2) index = 1; } ret = setjmp(jmpbuf_1); if(ret == 0) { printf("Orig setjmp\n"); } else if(ret == 1) { printf("Return From longjmp 1\n"); printf("Global_a: %d\n", g_a); printf("Local_a: %d\n", l_a); return 0; } else if(ret == 2) { printf("Return From longjmp 2\n"); printf("Global_a: %d\n", g_a); printf("Local_a: %d\n", l_a); return 0; } test(index, &l_a); return 0; } |
wangyao@wangyao-laptop:~/Test/sys$ gcc longjmp.c -O2 wangyao@wangyao-laptop:~/Test/sys$ ./a.out 1 Orig setjmp Return From longjmp 1 Global_a: 1111 Local_a: 1 wangyao@wangyao-laptop:~/Test/sys$ ./a.out 2 Orig setjmp Return From longjmp 2 Global_a: 1111 Local_a: 1 wangyao@wangyao-laptop:~/Test/sys$ gcc longjmp.c wangyao@wangyao-laptop:~/Test/sys$ ./a.out 1 Orig setjmp Return From longjmp 1 Global_a: 1111 Local_a: 2222 wangyao@wangyao-laptop:~/Test/sys$ ./a.out 2 Orig setjmp Return From longjmp 2 Global_a: 1111 Local_a: 2222 |
ENTRY (BP_SYM (__sigsetjmp)) ENTER movl JMPBUF(%esp), %eax CHECK_BOUNDS_BOTH_WIDE (%eax, JMPBUF(%esp), $JB_SIZE) /* Save registers. */ movl %ebx, (JB_BX*4)(%eax) movl %esi, (JB_SI*4)(%eax) movl %edi, (JB_DI*4)(%eax) leal JMPBUF(%esp), %ecx /* Save SP as it will be after we return. */ #ifdef PTR_MANGLE PTR_MANGLE (%ecx) #endif movl %ecx, (JB_SP*4)(%eax) movl PCOFF(%esp), %ecx /* Save PC we are returning to now. */ #ifdef PTR_MANGLE PTR_MANGLE (%ecx) #endif movl %ecx, (JB_PC*4)(%eax) LEAVE /* pop frame pointer to prepare for tail-call. */ movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer. */ #if defined NOT_IN_libc && defined IS_IN_rtld /* In ld.so we never save the signal mask. */ xorl %eax, %eax ret #else /* Make a tail call to __sigjmp_save; it takes the same args. */ jmp __sigjmp_save #endif |
#ifdef PTR_DEMANGLE movl JBUF(%esp), %eax /* User's jmp_buf in %eax. */ CHECK_BOUNDS_BOTH_WIDE (%eax, JBUF(%esp), $JB_SIZE) /* Save the return address now. */ movl (JB_PC*4)(%eax), %edx /* Get the stack pointer. */ movl (JB_SP*4)(%eax), %ecx PTR_DEMANGLE (%edx) PTR_DEMANGLE (%ecx) cfi_def_cfa(%eax, 0) cfi_register(%eip, %edx) cfi_register(%esp, %ecx) cfi_offset(%ebx, JB_BX*4) cfi_offset(%esi, JB_SI*4) cfi_offset(%edi, JB_DI*4) cfi_offset(%ebp, JB_BP*4) /* Restore registers. */ movl (JB_BX*4)(%eax), %ebx movl (JB_SI*4)(%eax), %esi movl (JB_DI*4)(%eax), %edi movl (JB_BP*4)(%eax), %ebp cfi_restore(%ebx) cfi_restore(%esi) cfi_restore(%edi) cfi_restore(%ebp) movl VAL(%esp), %eax /* Second argument is return value. */ movl %ecx, %esp #else movl JBUF(%esp), %ecx /* User's jmp_buf in %ecx. */ CHECK_BOUNDS_BOTH_WIDE (%ecx, JBUF(%esp), $JB_SIZE) movl VAL(%esp), %eax /* Second argument is return value. */ /* Save the return address now. */ movl (JB_PC*4)(%ecx), %edx /* Restore registers. */ movl (JB_BX*4)(%ecx), %ebx movl (JB_SI*4)(%ecx), %esi movl (JB_DI*4)(%ecx), %edi movl (JB_BP*4)(%ecx), %ebp movl (JB_SP*4)(%ecx), %esp #endif /* Jump to saved PC. */ jmp *%edx END (BP_SYM (__longjmp)) |
#include #include #include #include /* Jump buffer */ static sigjmp_buf jmpbuf; /* Signal handler */ static void myfunc(int signo) { printf("SIGQUIT\n"); sleep(1); siglongjmp(jmpbuf, 1); } int main() { char *p = NULL; struct sigaction act; act.sa_handler = myfunc; act.sa_flags = SA_INTERRUPT; sigemptyset(&act.sa_mask); if (sigaction(SIGQUIT, &act, NULL) < 0) perror("sigaction"); if (sigsetjmp(jmpbuf, 1) == 1) { printf("I'm jumped\n"); } else { /* SIGSEGV */ raise(SIGQUIT); } /* JUMP */ printf("I'm here\n"); return 0; } |
wangyao@wangyao-laptop:~/Test/sys$ ./a.out SIGQUIT I'm jumped I'm here |