找出有多少字节将 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位,就像esp
和ebp
一样。 (尽管在内部 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
指令将返回地址放在堆栈上。调用后转移到functioname
ESP 指向栈顶的返回地址。 push %ebp
将 ESP 减少 4 并将 EBP 的副本放在那里。改变 ESP 的下一条指令是sub $0x70,%esp
。这会从 ESP 中减去 0x70(112)。两个movl
指令根本不会改变 ESP 因此可以忽略。所以当所有的指令都执行完时,ESP就是返回地址的0x70+0x04=0x74字节以上是关于找出有多少字节将 esp 和程序堆栈上存储的返回地址分开的主要内容,如果未能解决你的问题,请参考以下文章