看看安装在Ubuntu 9.04中的ld.so的反汇编(连同指令跟踪),我发誓我有时会看到数据存储在堆栈指针下面(即超出堆栈顶部)。这对我来说似乎很疯狂,但也许这比我想象的更常见。这经常发生吗?
这就是我所看到的:
ebp: 0xBF8269E8, esp: 0xBF8269DC
c98: 8b 45 f0 mov -0x10(%ebp),%eax
c9b: 8d 14 06 lea (%esi,%eax,1),%edx
c9e: 8b 83 28 03 00 00 mov 0x328(%ebx),%eax
ca4: 3b 50 04 cmp 0x4(%eax),%edx
答案 0 :(得分:1)
究竟是什么让您相信存储在堆栈指针下面的东西。我只能看到ebp
的负偏移,它是 frame 指针。
由于多种原因,它通常用作指向下一个堆栈帧的指针。
ebp
的任何一方都是传递给此函数的参数(在ebp
之上)和此函数的本地符号(在ebp
之下)。使用-0x10(%ebp)
只意味着您正在使用局部变量执行某些操作。%esp
加载到%ebp
并返回即可轻松恢复到之前的堆栈框架。当然,可能会点击%esp
以下的内容,但这取决于所加载的数据,实际上并未在您的示例中显示。
“图表”可能有所帮助:
+------------------------+
| Parameters passed to x |
+------------------------+
| Return address |
%ebp +------------------------+
| Locals for x |
%esp +------------------------+
我对此的记忆是生锈的(具体指令可能不准确,但它们应该足以表明其背后的概念),但典型的函数调用序列是:
push
,push
,...)。%ebp
推送到堆栈(push %ebp
)。%ebp
%esp%
(mov %ebp, %esp
)call XYZ
sub %esp,N
)。(%ebp+N)
)。(%ebp-N)
作为参数,%esp
作为本地人。并且,返回:
%ebp
加载mov %esp, %ebp
(ret
)。%ebp
)。pop %ebp
弹出堆栈(add %esp,N
)。答案 1 :(得分:1)
信号处理程序需要能够随时创建堆栈帧。因此,您始终需要遵循ABI的堆栈协议。
在PowerPC上,在堆栈指针下面保留一定数量的字节(半个千字节?)。 (当然,这可能因平台而异。)然后,信号处理人员必须浪费那么多空间以避免干扰任何事情。优点是消除了商店+减去并添加了为非常小的叶子函数创建框架的指令。