为什么 setjmp 传统上保存寄存器?

发布于 2025-01-06 21:51:49 字数 441 浏览 1 评论 0原文

仅以 i386 为例,但类似的问题也适用于其他架构。 setjmp保存的传统i386 jmp_buf由6个保存的寄存器组成:ebxesiedi< /code>、ebpespeip。其中,前 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

他不在意 2025-01-13 21:51:49

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 ;)

心病无药医 2025-01-13 21:51:49

您假设 setjump 会覆盖这些值(一个合理的假设),但是,我怀疑它可以,因为这会导致 longjmp 目标不稳定,从而无法使用。

假设ebx中有一个指针进入setjmp,当longjmp返回时,该指针必须被恢复,否则我们可能会得到一个很好的异常,从而破坏了非本地 goto 的全部意义。

更实际地看一下,我们可以看到 MS CRT 在保存寄存器之前不会污染它们:

MSVCR100._setjmp3 7>MOV EDX,DWORD PTR SS:[ESP+4]
73A030C4            MOV DWORD PTR DS:[EDX],EBP
73A030C6            MOV DWORD PTR DS:[EDX+4],EBX
73A030C9            MOV DWORD PTR DS:[EDX+8],EDI
73A030CC            MOV DWORD PTR DS:[EDX+C],ESI
73A030CF            MOV DWORD PTR DS:[EDX+10],ESP
73A030D2            MOV EAX,DWORD PTR SS:[ESP]
73A030D5            MOV DWORD PTR DS:[EDX+14],EAX
73A030D8            MOV DWORD PTR DS:[EDX+20],56433230
73A030DF            MOV DWORD PTR DS:[EDX+24],0
73A030E6            MOV EAX,DWORD PTR FS:[0]
73A030EC            MOV DWORD PTR DS:[EDX+18],EAX
73A030EF            CMP EAX,-1
73A030F2            JNZ SHORT MSVCR100.73A030FD
73A030F4            MOV DWORD PTR DS:[EDX+1C],-1
73A030FB            JMP SHORT MSVCR100.73A03138
73A030FD            MOV ECX,DWORD PTR SS:[ESP+8]
73A03101            OR ECX,ECX                                                   ;  Switch (cases 0..8)
73A03103            JE SHORT MSVCR100.73A0310F
73A03105            MOV EAX,DWORD PTR SS:[ESP+C]
73A03109            MOV DWORD PTR DS:[EDX+24],EAX
73A0310C            DEC ECX
73A0310D            JNZ SHORT MSVCR100.73A03117
73A0310F            MOV EAX,DWORD PTR DS:[EAX+C]                                 ;  Cases 0,1 of switch 73A03101
73A03112            MOV DWORD PTR DS:[EDX+1C],EAX
73A03115            JMP SHORT MSVCR100.73A03138
73A03117            MOV EAX,DWORD PTR SS:[ESP+10]
73A0311B            MOV DWORD PTR DS:[EDX+1C],EAX
73A0311E            DEC ECX
73A0311F            JE SHORT MSVCR100.73A03138
73A03121            PUSH ESI
73A03122            PUSH EDI
73A03123            LEA ESI,DWORD PTR SS:[ESP+1C]
73A03127            LEA EDI,DWORD PTR DS:[EDX+28]
73A0312A            CMP ECX,6
73A0312D            JBE SHORT MSVCR100.73A03134
73A0312F            MOV ECX,6                                                    ;  Default case of switch 73A03101
73A03134            REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]               ;  Cases 3,4,5,6,7,8 of switch 73A03101
73A03136            POP EDI
73A03137            POP ESI
73A03138            SUB EAX,EAX                                                  ;  Case 2 of switch 73A03101
73A0313A            RETN

更新

有一个 标准文档 规定必须保护环境:

对 setjmp() 的调用应将调用环境保存在其环境中
供 longjmp() 稍后使用的参数。

You are assuming setjump will overwrite those values (a fair assumption), however, I doubt that it could, because that would cause to make longjmp targets unstable, making it impossible to use.

lets say ebx had a pointer in it going into setjmp, when longjmp 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:

MSVCR100._setjmp3 7>MOV EDX,DWORD PTR SS:[ESP+4]
73A030C4            MOV DWORD PTR DS:[EDX],EBP
73A030C6            MOV DWORD PTR DS:[EDX+4],EBX
73A030C9            MOV DWORD PTR DS:[EDX+8],EDI
73A030CC            MOV DWORD PTR DS:[EDX+C],ESI
73A030CF            MOV DWORD PTR DS:[EDX+10],ESP
73A030D2            MOV EAX,DWORD PTR SS:[ESP]
73A030D5            MOV DWORD PTR DS:[EDX+14],EAX
73A030D8            MOV DWORD PTR DS:[EDX+20],56433230
73A030DF            MOV DWORD PTR DS:[EDX+24],0
73A030E6            MOV EAX,DWORD PTR FS:[0]
73A030EC            MOV DWORD PTR DS:[EDX+18],EAX
73A030EF            CMP EAX,-1
73A030F2            JNZ SHORT MSVCR100.73A030FD
73A030F4            MOV DWORD PTR DS:[EDX+1C],-1
73A030FB            JMP SHORT MSVCR100.73A03138
73A030FD            MOV ECX,DWORD PTR SS:[ESP+8]
73A03101            OR ECX,ECX                                                   ;  Switch (cases 0..8)
73A03103            JE SHORT MSVCR100.73A0310F
73A03105            MOV EAX,DWORD PTR SS:[ESP+C]
73A03109            MOV DWORD PTR DS:[EDX+24],EAX
73A0310C            DEC ECX
73A0310D            JNZ SHORT MSVCR100.73A03117
73A0310F            MOV EAX,DWORD PTR DS:[EAX+C]                                 ;  Cases 0,1 of switch 73A03101
73A03112            MOV DWORD PTR DS:[EDX+1C],EAX
73A03115            JMP SHORT MSVCR100.73A03138
73A03117            MOV EAX,DWORD PTR SS:[ESP+10]
73A0311B            MOV DWORD PTR DS:[EDX+1C],EAX
73A0311E            DEC ECX
73A0311F            JE SHORT MSVCR100.73A03138
73A03121            PUSH ESI
73A03122            PUSH EDI
73A03123            LEA ESI,DWORD PTR SS:[ESP+1C]
73A03127            LEA EDI,DWORD PTR DS:[EDX+28]
73A0312A            CMP ECX,6
73A0312D            JBE SHORT MSVCR100.73A03134
73A0312F            MOV ECX,6                                                    ;  Default case of switch 73A03101
73A03134            REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]               ;  Cases 3,4,5,6,7,8 of switch 73A03101
73A03136            POP EDI
73A03137            POP ESI
73A03138            SUB EAX,EAX                                                  ;  Case 2 of switch 73A03101
73A0313A            RETN

Update

there is a standards document that states it must preserve the environment:

A call to setjmp() shall save the calling environment in its env
argument for later use by longjmp().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文