找出有多少字节将 esp 和程序堆栈上存储的返回地址分开

Posted

技术标签:

【中文标题】找出有多少字节将 esp 和程序堆栈上存储的返回地址分开【英文标题】:Finding out how many bytes separate esp and the stored return address on the program's stack 【发布时间】:2017-08-15 00:30:10 【问题描述】:

我很难找到答案。从我读到的 %ebp 有 32 位,将 %esp 移动到 %ebp 你仍然有 32 位,然后减去 70 到 32,其余的我不明白。我是新手,所以我不是很熟练。请给出详细的解释。谢谢!

以下是我遇到的问题。

在这个指令序列的末尾,有多少字节将 esp 和存储在程序堆栈上的返回地址分开?假设我们使用标准 32 位 x86 调用约定调用此函数。

804847c functioname:
804847c: push %ebp
804847d: mov %esp,%ebp
804847f: sub $0x70,%esp
8048482: movl $0x0,0x4(%esp)
804848a: movl $0x8048580,(%esp)

【问题讨论】:

这条指令sub $0x70,%esp中的$0x70值被符号扩展为32位,所以它也有32位,就像espebp一样。 (尽管在内部 0x70 值在指令中仅以 8 位编码,但这不是它的使用方式,这只是在这种特殊情况下的存储优化)。使用的位数限制了可以在这些位中编码的不同值的数量,即 8 位可以解释为从 0 到 255,或从 -128 到 +127 的值,或八个 1 位标志(开/关)。在您的问题中,这并不重要,因为所有涉及的值都是 32b。 【参考方案1】:

sub $0x70,%esp:在堆栈上保留 0x70 个字节。

movl $0x0,0x4(%esp) : 放置一个 0 32 位值作为参数。

movl $0x8048580,(%esp) :放置一个地址。下一个 ret 会跳转到它。

按照名为cdecl 的标准调用约定,参数被放置在堆栈上,后跟被调用者应返回的地址。

【讨论】:

这似乎不对。 ESP 已向下调整 0x70(112 字节)。在sub 指令之后,EBP 的临时副本位于 ESP + 0x70,返回地址位于 ESP + 0x74。 0x04(%esp) 和 (%esp) 实际上指向使用sub $0x70,%esp 指令在堆栈上创建的局部变量区域 在我看来,实际问题的答案是 ESP 和返回地址之间的差异是 0x70+ 0x04 (4 个字节用于 EBP 的推送我>)。它是 116 十进制或 0x74 十六进制。 应该指出movl 指令——我们不知道它们的用途。他们在问题中的实际包含实际上并没有改变 ESP 和返回地址之间的差异。它们实际上只是一条红鲱鱼。这闻起来像家庭作业,很可能教师希望用最后两条指令混淆学生。 @MichaelPetch 您能否向我详细解释一下您是如何得出这个答案的?比如为什么只使用“sub $0x70,%esp”和“movl $0x0,0x4(%esp)”?为什么其他的没有计算?提前感谢您,非常感谢您的意见。 当函数 functioname 被调用时,call 指令将返回地址放在堆栈上。调用后转移到functionameESP 指向栈顶的返回地址。 push %ebp 将 ESP 减少 4 并将 EBP 的副本放在那里。改变 ESP 的下一条指令是sub $0x70,%esp。这会从 ESP 中减去 0x70(112)。两个movl 指令根本不会改变 ESP 因此可以忽略。所以当所有的指令都执行完时,ESP就是返回地址的0x70+0x04=0x74字节

以上是关于找出有多少字节将 esp 和程序堆栈上存储的返回地址分开的主要内容,如果未能解决你的问题,请参考以下文章

Linux内核分析 02

数据压入堆栈时,ESP寄存器的指向?

汇编语言常用指令

操作系统工作流程

ESP寄存器和SS寄存器有什么区别?

如何在堆栈上创建大小为 x 的数组并将 scanf 值放入其中