2009-12-01 41 views
9

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

回答

8

在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”,以便讨论实施它们所涉及的一些问题。更现代化的芯片使它很难实现得很好。

4

setjmp/longjmp/sigsetjmp高度依赖CPU架构,操作系统和线程模型。在I/O错误或其他恶劣的情况下,前两个函数着名(或根据您的POV而臭名昭着)(取决于您的POV)出现在原始Unix内核中,作为“结构化”的方式来退出系统调用失败。

结构在/usr/include/setjmp.h(Linux Fedora)中的注释说调用环境,加上可能保存的信号掩码。它包含/usr/include/bits/setjmp.h来声明jmp_buf有一个由6个32位整数组成的数组,显然特定于x86系列。

虽然我找不到除PPC implementation之外的其他源,但有合理的评论暗示应该保存FPU设置。这是有道理的,因为未能恢复舍入模式,默认操作数大小,异常处理等将是令人惊讶的。

系统工程师通常会在这种结构中预留比实际需要更多的空间。几个额外的字节几乎不会出汗 - 特别是考虑到setjmp/longjmp的实际使用的稀少。太少的空间绝对是一种危险。我能想到的最显着的原因是有额外的 - 而不是现在 - 是如果运行时库版本更改为需要更多的空间在jmp_buf中,通过有额外的空间已经保留,没有必要重新编译程序指的是它。

相关问题