我正在运行Ubuntu 9.10(Karmic Koala),我看了一下jmp_buf
结构,它只是一个12个整数的数组。当我使用setjmp
并传入jmp_buf
结构时,12个条目中的4个将被保存。这4个条目是堆栈指针,帧指针,程序计数器和返回地址。其他8个条目是什么?它们是机器相关的吗?段表基址寄存器的另一个条目是?还有什么需要正确恢复线程/进程的环境?我查看了手册页,其他来源,但我找不到setjmp
的汇编代码。
答案 0 :(得分:9)
在MacOS X 10.6.2上,标题<setjmp.h>
最终使用<i386/setjmp.h>
,并在其中显示:
#if defined(__x86_64__)
/*
* _JBLEN is number of ints required to save the following:
* rflags, rip, rbp, rsp, rbx, r12, r13, r14, r15... these are 8 bytes each
* mxcsr, fp control word, sigmask... these are 4 bytes each
* add 16 ints for future expansion needs...
*/
#define _JBLEN ((9 * 2) + 3 + 16)
typedef int jmp_buf[_JBLEN];
typedef int sigjmp_buf[_JBLEN + 1];
#else
/*
* _JBLEN is number of ints required to save the following:
* eax, ebx, ecx, edx, edi, esi, ebp, esp, ss, eflags, eip,
* cs, de, es, fs, gs == 16 ints
* onstack, mask = 2 ints
*/
#define _JBLEN (18)
typedef int jmp_buf[_JBLEN];
typedef int sigjmp_buf[_JBLEN + 1];
#endif
您可能会在Linux上找到类似的要求 - jmp_buf
包含足够的信息来存储必要的状态。而且,要使用它,你真的不需要知道它包含什么;你需要做的就是相信实施者得到了正确的答案。如果你想改变实现,那么你当然需要理解它。
请注意,setjmp和longjmp是非常特定于机器的。阅读Plauger的“The Standard C Library”,讨论实施它们所涉及的一些问题。更现代的芯片使得实施起来更加困难。
答案 1 :(得分:5)
setjmp
/ longjmp
/ sigsetjmp
高度依赖于CPU架构,操作系统和线程模型。前两个函数着名(或臭名昭着 - 取决于你的POV)出现在原始的Unix内核中,作为一种“结构化”的方式来解除失败的系统调用,如来自i / o错误或其他令人讨厌的情况。
结构在/usr/include/setjmp.h(Linux Fedora)中的注释说调用环境,可能还有一个保存的信号掩码。它包括/usr/include/bits/setjmp.h到声明jmp_buf有一个由六个32位整数组成的数组,显然特定于x86系列。
虽然我找不到PPC implementation以外的来源,但其中的评论合理地提示应保存FPU设置。这是有道理的,因为无法恢复舍入模式,默认操作数大小,异常处理等将是令人惊讶的。
系统工程师通常会在这样的结构中保留比实际需要更多的空间。一些额外的字节几乎没有任何问题 - 特别是考虑到setjmp
/ longjmp
的实际使用的罕见性。空间太小肯定是危险的。我能想到的最显着的原因是,如果将运行时库版本更改为需要更多空间在jmp_buf中,通过额外的空间已经保留,则不需要重新编译引用的程序。它