【问题标题】:What happens when I move %esp to %ebp?当我将 %esp 移动到 %ebp 时会发生什么?
【发布时间】:2015-02-25 09:33:34
【问题描述】:

我知道这是一个非常基本的问题,但在这里:

我开始学习汇编程序,并试图了解堆栈的工作原理。

首先,当我将值传递给汇编函数时,我会像这样访问它:

movl 4(%esp),%eax  # first parameter
movl 8(%esp),%ebx  # second parameter

但后来有人告诉我最好这样做:

push %ebp
movl %esp,%ebp
# and then I'd access the values on %ebp:
movl 8(%ebp),%eax
movl 12(%ebp),%eax
pop %ebp

好的,这里有什么区别?当我直接从 %esp 访问这些值时,它们不是已经在堆栈上了吗?用 push 再做一次有什么好处?

有没有人有关于如何学习堆栈如何工作以便学习这些堆栈指针、返回地址等的好的学习工具(针对傻瓜型)的提示?我还没有找到任何关于它如何工作的好的视觉演示。 谢谢!

【问题讨论】:

  • 假设你在你的函数中将一些东西压入堆栈。如果您将当前堆栈指针复制到函数开头的ebp,则在访问参数时不必跟踪对esp 所做的更改。
  • 谢谢,@Michael。我想我只是对他们每个人(%ebp%esp)所做的事情以及我应该如何跟踪堆栈和地址感到困惑。
  • 顺便说一句,第二个并不好,除非有别的东西强迫你建立一个标准的堆栈框架。这显然是更多的指令,而且您通常不会在设置本地后更改 esp,因此 esp 与 ebp 一样稳定。
  • 你应该在互联网上找到很多关于堆栈如何工作的好草图。也许谷歌书籍也可以帮助你。当您想了解 EBP 的用途时,您需要在 Google 上搜索“堆栈框架”。堆栈框架是在堆栈“内部”创建的自制结构。这是高级编程语言编译器在调用函数时生成的东西。每次调用函数时,编译器都会为被调用函数创建一个栈帧。但是当您自己编写汇编代码时,您可以根据需要手动创建堆栈帧。但你不必这样做。
  • 使用 EBP 而不是 ESI 的原因是因为 EBP 默认访问堆栈段,而 ESI 访问数据段。这些可以被覆盖,但目的是让寄存器以这种方式使用。

标签: assembly stack


【解决方案1】:

在大多数情况下使用 %ebp 有历史原因:在 16 位程序中,x86 CPU 不支持诸如“movw 2(%sp), %ax”之类的指令,因为 x86 CPU 仅支持 %bx, %si, %di和 %bp 寄存器用于内存寻址。因此,在 16 位程序中,您不能使用 %sp,因此您可以使用 %bp。

当使用优化良好的现代编译器时,您将不会再在 32 位代码中看到“push”和“mov %esp,%ebp”指令,但代码看起来就像您的第一个示例(“4(% esp)" 而不是 "8(%ebp)")。

此类编译器有时会出于不同目的使用 %ebp 寄存器。

有一个用例仍然需要 %ebp: alloca() 函数:该函数通过执行“sub %eax, %esp”(或类似的)指令在堆栈上保留内存。在此说明之后,您将不再知道您的论点在哪里。

但是,在具有“平面”内存布局 (%ds=%ss) 的 32 位代码中,您也可以使用任何其他寄存器来代替 %ebp。

【讨论】:

  • 谢谢@Martin。但是,如果我需要局部变量,使用 %ebp 不是更好吗,这样我就不会混淆曾经的 4(%esp) 然后变成 8(%esp) 并在堆栈中添加一些东西?
  • 如果您手动编写较大的汇编代码,您是对的。对于较小的汇编代码,您可以对所有推送/弹出操作有一个概述,因此您可以使用 x(%esp) 。对于已编译的代码,这不是参数,因为编译器不会“混淆”。
【解决方案2】:

区别和原因都与堆栈帧有关。以下链接有一个相当不错的摘要(如果我自己这么说的话)。

What is stack frame in assembly?

【讨论】:

  • 谢谢,@Sparky。这是迄今为止最好的堆栈教程。我现在还没有完全明白,但我明白了很多。不过,我仍然不知道: 1 - 什么时候事情会隐含在堆栈上? 2 - 基指针到底是做什么用的? 3 - 由于将%ebp 推入堆栈有助于更轻松地跟踪我的变量,我应该在每个函数上使用它吗?
  • @francisaugusto - 基指针用于标记您当前的堆栈帧。即使您将更多内容推入堆栈,EBP 也不会更改,直到您进入下一个/上一个堆栈帧(但 ESP 会)。作为一般规则,如果您的例程调用另一个例程,则使用 E​​BP 和堆栈框架概念。如果不是,它是可选的。你越习惯它,当你不需要它的时候,你就会学得越多。最后,通常只有少数情况下您可能需要担心隐式堆栈推送:这些包括调用、中断和异常。
猜你喜欢
  • 2011-01-31
  • 2014-11-11
  • 1970-01-01
  • 2013-02-07
  • 2011-08-23
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
相关资源
最近更新 更多