将数据存储在堆栈指针下面?

时间:2010-02-22 03:11:22

标签: x86 stack

看看安装在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

2 个答案:

答案 0 :(得分:1)

究竟是什么让您相信存储在堆栈指针下面的东西。我只能看到ebp的负偏移,它是 frame 指针。

由于多种原因,它通常用作指向下一个堆栈帧的指针。

  • ebp的任何一方都是传递给此函数的参数(在ebp之上)和此函数的本地符号(在ebp之下)。使用-0x10(%ebp)只意味着您正在使用局部变量执行某些操作。
  • 只需将%esp加载到%ebp并返回即可轻松恢复到之前的堆栈框架。

当然,可能会点击%esp以下的内容,但这取决于所加载的数据,实际上并未在您的示例中显示。

“图表”可能有所帮助:

     +------------------------+
     | Parameters passed to x |
     +------------------------+
     | Return address         |
%ebp +------------------------+
     | Locals for x           |
%esp +------------------------+

我对此的记忆是生锈的(具体指令可能不准确,但它们应该足以表明其背后的概念),但典型的函数调用序列是:

  • 调用者在堆栈上推送参数(pushpush,...)。
  • 调用者将当前%ebp推送到堆栈(push %ebp)。
  • 来电者%ebp %esp%mov %ebp, %esp
  • 加载call XYZ
  • 来电者呼叫被叫方(sub %esp,N)。
  • callee为本地人分配空间((%ebp+N))。
  • callee可以使用(%ebp-N)作为参数,%esp作为本地人。

并且,返回:

  • 被叫方%ebp加载mov %esp, %ebpret)。
  • 被叫方返回来电者(%ebp)。
  • 来电者将前一个pop %ebp弹出堆栈(add %esp,N)。
  • 来电者清理参数部分({{1}})。

答案 1 :(得分:1)

信号处理程序需要能够随时创建堆栈帧。因此,您始终需要遵循ABI的堆栈协议。

在PowerPC上,在堆栈指针下面保留一定数量的字节(半个千字节?)。 (当然,这可能因平台而异。)然后,信号处理人员必须浪费那么多空间以避免干扰任何事情。优点是消除了商店+减去并添加了为非常小的叶子函数创建框架的指令。