为什么 setjmp 传统上保存寄存器?
仅以 i386 为例,但类似的问题也适用于其他架构。 setjmp
保存的传统i386 jmp_buf
由6个保存的寄存器组成:ebx
、esi
、edi< /code>、
ebp
、esp
和 eip
。其中,前 4 个是根据 ABI 调用者保存的,因此调用 setjmp
的函数本身将用自己保存的值覆盖它们(在 的第一次和第二次返回之间可能会发生变化) setjmp
)。因此,将这些寄存器保存在 jmp_buf 中有何意义?仅保存堆栈和指令指针不是同样有效吗?
编辑:我错误地混淆了调用者保存和被调用者保存,这就是混乱的全部根源。抱歉浪费了大家的时间。
Just consider i386 as an example, but an analogous question applies to other archs. The traditional i386 jmp_buf
saved by setjmp
consists of 6 saved registers: ebx
, esi
, edi
, ebp
, esp
, and eip
. Of these, the first 4 are caller-saved per the ABI, so the function that called setjmp
will itself overwrite them with its own saved values (which may change between the first and second return from setjmp
). Thus, what is the point in saving these registers at all in the jmp_buf
? Wouldn't it work just as well to save only the stack and instruction pointers?
Edit: I was mistakenly mixing up caller-saved and callee-saved, which was the entire source of the confusion. Apologies for wasting everybody's time.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
setjmp/longjmp 对不是“转到”,它们是“保存状态/恢复状态”组合...如果大多数寄存器未保存,则这是不可能的;例外是子例程返回寄存器,因此您可以确定您是从对 setjmp 的正常调用返回,还是通过 longjmp 返回。
编辑——虽然你问的四个应该是调用者保存的,但 setjmp() 不会信任你......并且无论你做了什么,它都会做正确的事情;)
The setjmp/longjmp pair are not a "goto", they're a "save-state / restore-state" combo... this would not be possible if most of the registers were not saved; the exception being the subroutine return register, so you can identify if you returned from a normal call to setjmp, or via a longjmp.
Edit -- though the four you question are supposed to be caller saved, setjmp() isn't going to trust you... and it's going to do the right thing regardless of what you did ;)
您假设 setjump 会覆盖这些值(一个合理的假设),但是,我怀疑它可以,因为这会导致 longjmp 目标不稳定,从而无法使用。
假设
ebx
中有一个指针进入setjmp
,当longjmp
返回时,该指针必须被恢复,否则我们可能会得到一个很好的异常,从而破坏了非本地 goto 的全部意义。更实际地看一下,我们可以看到 MS CRT 在保存寄存器之前不会污染它们:
更新
有一个 标准文档 规定必须保护环境:
You are assuming
setjump
will overwrite those values (a fair assumption), however, I doubt that it could, because that would cause to makelongjmp
targets unstable, making it impossible to use.lets say
ebx
had a pointer in it going intosetjmp
, whenlongjmp
returns, that pointer must be restored, else we might get a nice exception, thus defeating the whole point of a non-local goto.Taking a more practical look, we can see that the MS CRT doesn't tainted the registers before saving them:
Update
there is a standards document that states it must preserve the environment: