如上所述,调用jmp_buf
时,x86-64处理器上的setjmp(jmp_buf env)
需要处理哪种软件可视处理器状态?什么处理器状态不?
我一直在阅读很多关于setjmp
和longjmp
的内容,但无法找到我的问题的明确答案。我知道这是依赖于实现的,但我想知道x86_64架构。
来自following implementation
似乎在x86-64机器上需要保存所有被调用者保存的寄存器(%r12-%r15
,%rbp
,%rbx
)以及堆栈指针,程序计数器和所有已保存的寄存器当前环境的论据。但是我不确定,希望有人能为我澄清一下。
答案 0 :(得分:2)
例如,需要保存哪些x86-64寄存器?条件标志怎么样?例如,我认为不需要保存浮点寄存器,因为它们不会对程序的状态做出贡献。
这是因为调用约定。 setjmp
是一个函数调用,可以多次返回(第一次实际调用它时,稍后当子函数调用longjmp
时),但它仍然是一个函数调用。与任何函数调用一样,编译器假定所有调用被破坏的寄存器都已被破坏,因此longjmp
不需要恢复它们。
所以是的,他们不属于"计划状态"在函数调用边界上,因为编译器生成的asm肯定不会在其中保留任何值。
您正在查看glibc对x86-64 System V ABI的实现,其中所有 vector / x87寄存器都被调用破坏,因此没有被保存。
在Windows x86-64调用约定中,xmm6-15是调用保留的(只有低128位,而不是y / zmm6-15的上半部分),并且必须是{{1}的一部分}。
即。它不是与此相关的CPU架构,它是软件调用惯例。
除了保留呼叫保留的寄存器之外,一个关键的事情是它只对jmp_buf
到longjmp
合法的父函数保存是合法的,而不是来自函数之后的任何任意函数。被叫jmp_buf
的人已经回来了。
如果setjmp
必须支持,那么它必须保存整个堆栈帧,或实际上(为了能够返回的函数,以及能够返回的父级等)整个一直堆到顶部。这显然很疯狂,因此很清楚为什么setjmp
只能跳转到父/(大)祖父项功能,所以它只需要将堆栈指针恢复到指向仍然存在的堆栈帧并恢复自longjmp
以来该函数中的任何局部变量可能已被修改。
(关于使用除普通调用堆栈之外的其他东西的体系结构/调用约定的C / C ++实现,关于能够返回的跳转目标函数的类似参数仍然适用。)
答案 1 :(得分:0)
由于jmp_buf
是唯一可用于在longjmp
上恢复处理器状态的地方,因此通常需要恢复机器完整状态所需的一切,就像setjmp
时一样。 1}}被称为。
这显然在很大程度上取决于处理器和编译器(它使用CPU的功能来存储程序状态到底是什么):
jmp_buff
还需要存储此零页面的副本(某些65xx CPU或ATmel AVR MCU及其编译器可能会使用此功能)