longjmp 是如何工作的?
我需要了解 longjmp 函数是如何工作的;我知道它的作用,但我需要知道它是如何做到的。
我试图在 gdb 中禁用代码,但我无法理解一些步骤。代码是:
0xb7ead420 <siglongjmp+0>: push %ebp
0xb7ead421 <siglongjmp+1>: mov %esp,%ebp
0xb7ead423 <siglongjmp+3>: sub $0x18,%esp
0xb7ead426 <siglongjmp+6>: mov %ebx,-0xc(%ebp)
0xb7ead429 <siglongjmp+9>: call 0xb7e9828f <_Unwind_Find_FDE@plt+119>
0xb7ead42e <siglongjmp+14>: add $0x12bbc6,%ebx
0xb7ead434 <siglongjmp+20>: mov %esi,-0x8(%ebp)
0xb7ead437 <siglongjmp+23>: mov 0xc(%ebp),%esi
0xb7ead43a <siglongjmp+26>: mov %edi,-0x4(%ebp)
0xb7ead43d <siglongjmp+29>: mov 0x8(%ebp),%edi
0xb7ead440 <siglongjmp+32>: mov %esi,0x4(%esp)
0xb7ead444 <siglongjmp+36>: mov %edi,(%esp)
0xb7ead447 <siglongjmp+39>: call 0xb7ead4d0
0xb7ead44c <siglongjmp+44>: mov 0x18(%edi),%eax
0xb7ead44f <siglongjmp+47>: test %eax,%eax
0xb7ead451 <siglongjmp+49>: jne 0xb7ead470 <siglongjmp+80>
0xb7ead453 <siglongjmp+51>: test %esi,%esi
0xb7ead455 <siglongjmp+53>: mov $0x1,%eax
0xb7ead45a <siglongjmp+58>: cmove %eax,%esi
0xb7ead45d <siglongjmp+61>: mov %esi,0x4(%esp)
0xb7ead461 <siglongjmp+65>: mov %edi,(%esp)
0xb7ead464 <siglongjmp+68>: call 0xb7ead490
0xb7ead469 <siglongjmp+73>: lea 0x0(%esi,%eiz,1),%esi
0xb7ead470 <siglongjmp+80>: lea 0x1c(%edi),%eax
0xb7ead473 <siglongjmp+83>: movl $0x0,0x8(%esp)
0xb7ead47b <siglongjmp+91>: mov %eax,0x4(%esp)
0xb7ead47f <siglongjmp+95>: movl $0x2,(%esp)
0xb7ead486 <siglongjmp+102>: call 0xb7ead890 <sigprocmask>
0xb7ead48b <siglongjmp+107>: jmp 0xb7ead453 <siglongjmp+51>
有人可以简单解释一下代码,或者指出我在系统中哪里可以找到源代码吗?
I need to understand HOW longjmp function works; I know what it does, but I need to know how it does it.
I tried to disas the code in gdb but I can't understand some steps. The code is:
0xb7ead420 <siglongjmp+0>: push %ebp
0xb7ead421 <siglongjmp+1>: mov %esp,%ebp
0xb7ead423 <siglongjmp+3>: sub $0x18,%esp
0xb7ead426 <siglongjmp+6>: mov %ebx,-0xc(%ebp)
0xb7ead429 <siglongjmp+9>: call 0xb7e9828f <_Unwind_Find_FDE@plt+119>
0xb7ead42e <siglongjmp+14>: add $0x12bbc6,%ebx
0xb7ead434 <siglongjmp+20>: mov %esi,-0x8(%ebp)
0xb7ead437 <siglongjmp+23>: mov 0xc(%ebp),%esi
0xb7ead43a <siglongjmp+26>: mov %edi,-0x4(%ebp)
0xb7ead43d <siglongjmp+29>: mov 0x8(%ebp),%edi
0xb7ead440 <siglongjmp+32>: mov %esi,0x4(%esp)
0xb7ead444 <siglongjmp+36>: mov %edi,(%esp)
0xb7ead447 <siglongjmp+39>: call 0xb7ead4d0
0xb7ead44c <siglongjmp+44>: mov 0x18(%edi),%eax
0xb7ead44f <siglongjmp+47>: test %eax,%eax
0xb7ead451 <siglongjmp+49>: jne 0xb7ead470 <siglongjmp+80>
0xb7ead453 <siglongjmp+51>: test %esi,%esi
0xb7ead455 <siglongjmp+53>: mov $0x1,%eax
0xb7ead45a <siglongjmp+58>: cmove %eax,%esi
0xb7ead45d <siglongjmp+61>: mov %esi,0x4(%esp)
0xb7ead461 <siglongjmp+65>: mov %edi,(%esp)
0xb7ead464 <siglongjmp+68>: call 0xb7ead490
0xb7ead469 <siglongjmp+73>: lea 0x0(%esi,%eiz,1),%esi
0xb7ead470 <siglongjmp+80>: lea 0x1c(%edi),%eax
0xb7ead473 <siglongjmp+83>: movl $0x0,0x8(%esp)
0xb7ead47b <siglongjmp+91>: mov %eax,0x4(%esp)
0xb7ead47f <siglongjmp+95>: movl $0x2,(%esp)
0xb7ead486 <siglongjmp+102>: call 0xb7ead890 <sigprocmask>
0xb7ead48b <siglongjmp+107>: jmp 0xb7ead453 <siglongjmp+51>
Can someone briefly explain me the code, or indicate where I can find the source code in the system?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是
longjmp
的 i386 代码,采用标准 i386 ABI,没有任何与 C++ 交互的疯狂扩展、异常、清理函数、信号掩码等:Here is the i386 code for
longjmp
, in the standard i386 ABI, without any crazy extensions for interaction with C++, exceptions, cleanup functions, signal mask, etc.:大多数情况下,它会将寄存器和堆栈恢复为相应
setjmp()
时的状态。需要一些额外的清理(修复信号处理和展开待处理堆栈处理程序),以及返回不同的值作为 setjmp 的明显返回值,但恢复状态是操作的本质。为了使其正常工作,堆栈不能低于调用 setjmp 的点。 Longjmp 是一种粗暴的方法,它会忘记在它下面调用的所有内容,直到调用堆栈(或函数调用嵌套序列)中的同一级别,主要通过简单地将堆栈指针设置为调用 setjmp 时的同一帧来实现。
为了让它干净地工作,
longjmp()
调用中间函数的所有退出处理程序,以便它们可以删除变量,以及函数返回时通常执行的任何其他清理操作。将堆栈重置到较浅的深度会释放所有auto
变量,但如果其中一个是FILE *
,则需要关闭该文件并释放 i/o 缓冲区也。Mostly, it restores the registers and stack as they were at the time of the corresponding
setjmp()
. There is some additional cleanup required (fixing signal handling and unwinding pending stack handlers), as well as returning a different value as the apparent return value of setjmp, but restoring the state is the essence of the operation.For it to work, the stack cannot be below the point at which setjmp was called. Longjmp is a brutish way to just forget everything that has been called below it down to the same level in the call stack (or function call nesting sequence) mostly by simply setting the stack pointer to the same frame it was when setjmp was called.
For it to work cleanly,
longjmp()
calls all the exit handlers for intermediate functions, so they can delete variables, and whatever other cleanup is normally done when a function returns. Resetting the stack to a point less deep releases all theauto
variables but if one of those is aFILE *
, the file needs to be closed and the i/o buffer freed too.我认为您需要查看 过程激活记录和调用堆栈和Setjmp.h 的
jmp_buf
结构。引自《专家 C 编程:深度 C 秘密》:
有也请参见第 153 页。
堆栈框架将高度依赖于机器和可执行文件,但想法是相同的。
I think you need to see Procedure Activation Records and Call Stacks and Setjmp.h 's
jmp_buf
's structure.Quoted from Expert C Programming: Deep C Secrets:
Have a look at page 153 also here.
The stackframe will be highly dependent on the machine and the executable, but the idea is the same.
在 Windows X64 MASM 中
In Windows X64 MASM
您向 setjmp() 传递一个缓冲区参数。然后它将当前的寄存器信息等存储到该缓冲区中。然后调用 longjmp() 从缓冲区中恢复这些值。此外,沃利克所说的。
You pass setjmp() a buffer parameter. It then stores the current register info etc. into this buffer. The call to longjmp() then restores these values from the buffer. Furthermore, what wallyk said.
以下是我为一个小型 clib 子集编写的 setmp 和 longjmp 版本(在 Visual Studio 2008 中编写和测试)。汇编代码存储在单独的 .asm 文件中。
用于测试它的 AC 代码片段:
请注意,我使用了“setjmp.h”中的声明作为缓冲区,但如果您愿意,可以使用整数数组(至少 6 个整数)。
Here are versions of setmp and longjmp I wrote for a small clib subset (written and tested in Visual Studio 2008). The assembly code is stored in a separate .asm file.
A C code snippet to test it:
Note that I used the declaration from 'setjmp.h' for the buffer but if you want you can use an array of ints (minimum of 6 ints).