【问题标题】:Function prolog in terms of memory记忆方面的功能序言
【发布时间】:2016-09-28 18:17:51
【问题描述】:

我正在尝试了解函数 prolog 在汇编中的工作方式。我的书显示以下代码:

    push    %ebp
    movl    %ebp, %esp

在 push 的定义中,它说它将 ESP 的值递减 4(字节?),然后将操作数放入 ESP 指定的内存中。但是,这不会覆盖图中所示的一些数据吗?

另外我在这里假设每个段是 4 个(字节?)但是我很确定函数可以有超过 4 个字节的分配堆栈空间?

接下来,第二条指令将 ESP 的内容移动到 EBP 中,但是有什么需要呢?那已经存在了?当pop 被调用时,它如何知道从堆栈中取出多少? (我解释的所有内容都假设指令movpush 从它们指向的位置开始,并在执行任何操作时上内存)

【问题讨论】:

  • 在 AT&T 汇编中,您的 prolog 代码应该看起来像:pushl %ebpmovl %esp, %ebp。如果是错别字,请更正。

标签: memory assembly stack


【解决方案1】:

x86 机器上的堆栈从高地址向低地址增长。
这在push 指令的语义中得到体现:

push ebp

在语义上等价于

sub esp, 04h
mov DWORD [esp], ebp  

从技术上讲,我们说堆栈是完全下降完全因为esp总是指向最后一个被压入的值并且下降明显的原因。

事实上,堆栈指针上方的所有内容都已被某些代码推送,因此它被初始化并隐式分配内存。
反过来说,栈底下的所有东西都是空闲内存。

因此 push ebp 不会覆盖任何有用的东西,一般情况下 push 永远不会这样做。

mov ebp, esp 不采用 EBP 中的内容(本来应该是 mov ebp, DWORD [esp],而是将 ESP 寄存器的内容复制到 em>EBP
EBP 的使用有两个原因:

  1. 它隐式使用 SS 选择器,而其他寄存器使用 DS
  2. 在 16 位纯代码中,只有少数寄存器可以用作基址,(E)BP 是专门为此设计的。
    (E)BP 指向 ESP 的值对于随机访问堆栈并使用固定偏移量非常方便。

最后,pop 指令就像push 一样,它的操作数决定了操作的大小:push ax/eax/rax 分别压栈 2、4 和 8 个字节。
程序员仍然有责任保持堆栈平衡,如果需要甚至对齐,但这通常没有太多要求。


注意:x86 内存是字节可寻址的,因此当进行间接寄存器寻址时,即当我们访问在寄存器中指定的地址时,例如mov eax, DWORD [ebx],该数字以术语表示地址字节数。
将该数字减少 N 意味着读取 N 个字节,因此从 ESP 中减去 4 会在 中的新地址和旧地址之间留下四个字节ESP

【讨论】:

  • 当你说“esp”指向最后推送的值时;它是否指向最低的内存地址? (所以如果你推 0b0001 然后读 esp[0] 你会得到 1 还是 0?
  • 还有movepush'处理'寄存器的内容,而不是寄存器内容指定的内存
  • @Bula ESP 是堆栈指针,堆栈满降,ESP 保存最后一个值被压入的地址。如果您 push DWORD 1 后跟 mov eax, DWORD [esp],则 EAX 为 1。在 Intel 语法中,indirectdirect 寄存器寻址由使用来告知[].
  • 好吧。似乎我在想 ESP 指向已被推送到寄存器的最后一件事的结尾。因此,如果您有push DWORD 1 后跟move eax DWORD [esp],我的错误理解是eax 将是“1000 ....00”,但是根据我修改后的理解,它将是“0000...1”。我相信我错误地认为它是从高到低读取内存。
【解决方案2】:

布拉

寄存器推送消耗多少字节取决于寄存器大小,而这又是芯片架构的一个功能。在您的示例中,您使用的是 32 位寄存器,因此每次寄存器推送将消耗 4 个字节。

对于 x86 的解释,description 可能会很有帮助。

【讨论】:

    猜你喜欢
    • 2011-01-24
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2020-07-07
    • 2018-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多