在x86-64处理器上的jmp_buf需要什么软件可见的处理器状态?

时间:2018-01-31 14:25:30

标签: c assembly x86 x86-64 setjmp

如上所述,调用jmp_buf时,x86-64处理器上的setjmp(jmp_buf env)需要处理哪种软件可视处理器状态?什么处理器状态不?

我一直在阅读很多关于setjmplongjmp的内容,但无法找到我的问题的明确答案。我知道这是依赖于实现的,但我想知道x86_64架构。

来自following implementation 似乎在x86-64机器上需要保存所有被调用者保存的寄存器(%r12-%r15%rbp%rbx)以及堆栈指针,程序计数器和所有已保存的寄存器当前环境的论据。但是我不确定,希望有人能为我澄清一下。

2 个答案:

答案 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_buflongjmp合法的父函数保存是合法的,而不是来自函数之后的任何任意函数。被叫jmp_buf的人已经回来了。

如果setjmp必须支持,那么它必须保存整个堆栈帧,或实际上(为了能够返回的函数,以及能够返回的父级等)整个一直堆到顶部。这显然很疯狂,因此很清楚为什么setjmp只能跳转到父/(大)祖父项功能,所以它只需要将堆栈指针恢复到指向仍然存在的堆栈帧并恢复自longjmp以来该函数中的任何局部变量可能已被修改。

(关于使用除普通调用堆栈之外的其他东西的体系结构/调用约定的C / C ++实现,关于能够返回的跳转目标函数的类似参数仍然适用。)

答案 1 :(得分:0)

由于jmp_buf是唯一可用于在longjmp上恢复处理器状态的地方,因此通常需要恢复机器完整状态所需的一切,就像setjmp时一样。 1}}被称为。

这显然在很大程度上取决于处理器和编译器(它使用CPU的功能来存储程序状态到底是什么):

  • 在一个理想的纯堆栈机器上,它只保存堆栈中没有CPU状态的信息,这只是堆栈指针。除了非常古老或纯粹的学术实现之外,这种机器很少存在。但是,您可以在像x86这样的现代机器上编写编译器,它只使用堆栈来存储这些信息。对于这样一个假设的编译器,只保存堆栈指针就足以恢复程序状态。
  • 在一个更常见的实用机器上,这可能是堆栈指针和用于存储程序状态的完整寄存器集。
  • 在某些将程序状态信息存储在其他位置的CPU(例如零页面)和使用此类CPU功能的编译器上,jmp_buff还需要存储此零页面的副本(某些65xx CPU或ATmel AVR MCU及其编译器可能会使用此功能)