2

仅以 i386 为例,但类似的问题也适用于其他拱门。传统的 i386jmp_buf保存的setjmp由 6 个保存的寄存器组成:ebxesiediebpespeip. 其中,前 4 个是根据 ABI 调用者保存的,因此调用的函数setjmp本身会用自己保存的值覆盖它们(这可能在第一次和第二次 return from 之间发生变化setjmp)。因此,将这些寄存器保存在 中的意义jmp_buf何在?只保存堆栈和指令指针不是也一样吗?

编辑:我错误地混淆了调用者保存和被调用者保存,这是混乱的全部来源。抱歉浪费了大家的时间。

4

2 回答 2

5

setjmp/longjmp 对不是“goto”,它们是“save-state / restore-state”组合......如果大多数寄存器没有保存,这将是不可能的;例外是子例程返回寄存器,因此您可以确定您是从对 setjmp 的正常调用中返回,还是通过 longjmp。

编辑-尽管您提出的四个问题应该是调用者保存的,但 setjmp() 不会信任您……而且无论您做什么,它都会做正确的事情;)

于 2012-02-19T18:36:34.377 回答
0

您假设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() 的调用应将调用环境保存在其 env 参数中,以供 longjmp() 以后使用。

于 2012-02-19T19:57:45.100 回答