[C语言] 关于jmp_buf类型分析

软件和网站开发以及相关技术探讨
回复
leetking
帖子: 62
注册时间: 2014-10-28 14:53
系统: ubuntu-18.04-LTS

[C语言] 关于jmp_buf类型分析

#1

帖子 leetking » 2017-04-20 21:20

我在一个c语言实现的minigc源码(https://github.com/authorNari/minigc)的阅读中遇到一个问题。
关于编译jmp_buf类型变量,我已经查过了jmp_buf的含义,并且在google、wiki和stack overflow查询过相关问题没有结果。
疑惑代码如下,gc.c文件内的

代码: 全选

static void
gc_mark_register(void)
{
    jmp_buf env;
    size_t i;
    
    /*
     * 把当前栈的上下文存储到env里
     * 保存env的时候成功返回0
     * 以后可以通过调用longjmp(env, vlu);
     * 返回到最后一次注册到env里的setjmp出,并且此时setjmp返回vlu
     * jmp_buf 本质是一个类数组类型!
     */
    setjmp(env);
    /* TODO 为何会对jmp_buf进行这种hark的操作? */
    for (i = 0; i < sizeof(env); i++) {
        gc_mark(((void **)env)[i]);
    }
}
问题是我们遍历env变量能的得到什么信息呢?
头像
astolia
论坛版主
帖子: 6396
注册时间: 2008-09-18 13:11

Re: [C语言] 关于jmp_buf类型分析

#2

帖子 astolia » 2017-07-27 20:14

你直接看setjmp.h不就完了么
相关的定义如下:

代码: 全选

# if __WORDSIZE == 64
typedef long int __jmp_buf[8];
# elif defined  __x86_64__
__extension__ typedef long long int __jmp_buf[8];
# else
typedef int __jmp_buf[6];
# endif

/* Calling environment, plus possibly a saved signal mask.  */
struct __jmp_buf_tag
  {
    /* NOTE: The machine-dependent definitions of `__sigsetjmp'
       assume that a `jmp_buf' begins with a `__jmp_buf' and that
       `__mask_was_saved' follows it.  Do not move these members
       or add others before it.  */
    __jmp_buf __jmpbuf;     /* Calling environment.  */
    int __mask_was_saved;   /* Saved the signal mask?  */
    __sigset_t __saved_mask;    /* Saved signal mask.  */
  };

typedef struct __jmp_buf_tag jmp_buf[1];
你要理解它是在干什么,就需要一点汇编语言和操作系统相关的知识。上面代码中提到的Calling environment,实际上就是指的是CPU的寄存器的值,你看这个函数的名称gc_mark_register,就是在标记寄存器。

一个最简化的程序

代码: 全选

#include <setjmp.h>
int main(int argc,char **argv) {
	jmp_buf env;
	setjmp(env);
	return 0;
}
用gdb调试的结果,你可以自己看看env中包含的值与cpu寄存器的关系

代码: 全选

(gdb) break main
Breakpoint 1 at 0x738: file a.c, line 2.
(gdb) r
Starting program: /tmp/a.out 

Breakpoint 1, main (argc=1, argv=0x7fffffffdf78) at a.c:2
2	int main(int argc,char **argv) {
(gdb) s
4		setjmp(env);
(gdb) s
5		return 0;
(gdb) print env
$1 = {{__jmpbuf = {0, 5569584266273830259, 4294968816, 140737488346992, 0, 0, 5569584266370299251, -5569021317323737741}, 
    __mask_was_saved = 0, __saved_mask = {__val = {0, 0, 0, 0, 5658608, 194, 140737488346735, 140737488346734, 140737348619248, 1, 
        4294969293, 0, 0, 4294969216, 4294968816, 140737488346992}}}}
(gdb) info registers
rax            0x0	0
rbx            0x0	0
rcx            0x0	0
rdx            0x4d4b23619f9b3573	5569584266370299251
rsi            0x0	0
rdi            0x7fffffffddc0	140737488346560
rbp            0x7fffffffde90	0x7fffffffde90
rsp            0x7fffffffddb0	0x7fffffffddb0
r8             0x1000007f0	4294969328
r9             0x7ffff7de7f90	140737351942032
r10            0x2	2
r11            0x1	1
r12            0x1000005f0	4294968816
r13            0x7fffffffdf70	140737488346992
r14            0x0	0
r15            0x0	0
rip            0x100000756	0x100000756 <main+54>
eflags         0x246	[ PF ZF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
(gdb) 
leetking
帖子: 62
注册时间: 2014-10-28 14:53
系统: ubuntu-18.04-LTS

Re: [C语言] 关于jmp_buf类型分析

#3

帖子 leetking » 2017-07-27 21:47

谢谢,这个问题在问了之后没多久我通过其他渠道弄懂了。这里没有关闭它,谢谢您的回答。我再熟悉下。
回复