仅以i386为例,但类似的问题适用于其他拱门。由jmp_buf
保存的传统i386 setjmp
包含6个已保存的寄存器:ebx
,esi
,edi
,ebp
,esp
和eip
。其中,前4个是按ABI调用保存的,因此调用setjmp
的函数本身会用自己的保存值覆盖它们(可能会在setjmp
的第一次和第二次返回之间发生变化) 。那么,在jmp_buf
中保存这些寄存器有什么意义呢?它只能保存堆栈和指令指针吗?
编辑:我错误地将调用者保存和被调用者保存混淆,这是混乱的全部根源。抱歉浪费每个人的时间。
答案 0 :(得分:4)
setjmp / longjmp对不是“goto”,它们是“保存状态/恢复状态”组合......如果没有保存大多数寄存器,这是不可能的;例程是子程序返回寄存器,因此您可以识别是否从正常调用setjmp或通过longjmp返回。
编辑 - 虽然你问的四个人应该被调用者保存,但是setjmp()不会信任你......无论你做了什么,它都会做正确的事情;)
答案 1 :(得分:0)
您假设setjump
将覆盖这些值(公平的假设),但是,我怀疑它可能,因为这会导致longjmp
目标不稳定,使其无法使用。< / p>
让我们说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
<强>更新强>
有standards document表示必须保留环境:
对setjmp()的调用应将调用环境保存在其env中 参数供以后使用longjmp()。