Jmp_buf结构中的每个条目都有什么作用?

时间:2009-12-01 03:19:47

标签: c callstack longjmp

我正在运行Ubuntu 9.10(Karmic Koala),我看了一下jmp_buf结构,它只是一个12个整数的数组。当我使用setjmp并传入jmp_buf结构时,12个条目中的4个将被保存。这4个条目是堆栈指针,帧指针,程序计数器和返回地址。其他8个条目是什么?它们是机器相关的吗?段表基址寄存器的另一个条目是?还有什么需要正确恢复线程/进程的环境?我查看了手册页,其他来源,但我找不到setjmp的汇编代码。

2 个答案:

答案 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中,通过额外的空间已经保留,则不需要重新编译引用的程序。它