为什么在x86汇编中,leave指令要执行"mov esp,ebp"操作?

65

据说leave指令与以下内容相同:

mov esp,ebp
pop ebp

但是这里的mov esp,ebp是做什么的?它对我来说似乎不是有效的...


https://dev59.com/Q3RB5IYBdhLWcg3wl4IQ - Ciro Santilli OurBigBook.com
3个回答

94

mov esp, ebp指令将栈指针设置为基帧地址,有效释放整个栈帧。(不要忘记这是Intel语法,目的地在前面。)如果你没有执行此操作,在调用ret之后,你仍会使用被调用函数的栈帧与你的调用函数一起使用,可能会导致崩溃。


抱歉,但是 mov esp, ebp 不是将基指针设置为堆栈指针的地址吗?mov ebp, esp 才会更新堆栈指针以指向基础框架。 - Byte Lab
18
@Decave,这取决于您是使用AT&T样式反汇编还是Intel样式反汇编。由于指令没有长度后缀,并且寄存器没有以“%”为前缀,因此我们正在谈论Intel样式,在这种样式中目的地先出现。对于这个问题,您可能在考虑的等效的AT&T样式反汇编,其中目的地最后出现,将是movl %ebp,%esp - zneak
啊,当然。非常感谢您的解释。 - Byte Lab
您的网站 https://www.felixcloutier.com/x86/ 已经宕机(整个域名都不可访问)。您打算恢复它还是我应该开始编辑旧答案中的链接?(遗憾的是,旧评论中的链接指示是无法编辑的。) - Peter Cordes
1
@PeterCordes DNS由于某些悲伤的原因未能自动更新,应在TTL到期并刷新后尽快恢复在线。(对我来说它已经恢复在线了。) - zneak
显示剩余3条评论

4
我认为你的问题在于x86汇编有两种不同的写法,一种是AT&T符号,另一种是Intel符号。与AT&T符号相比,Intel符号中指令参数的顺序是反转的。你的汇编版本似乎是用Intel符号书写的,这意味着mov esp, ebp实际上将ebp中的值移动到了esp中。在更合理(我个人认为)的AT&T符号中应该是mov %ebp, %esp

1
这里应该使用 movd 而不是 mov - zneak
12
如果您将语义视为“将ebp移动到esp中”,那么这更符合逻辑。 “Intel”符号(早在英特尔之前很久就存在了 - 例如,追溯至60年代的Interdata 16位系列正是使用这种格式,并且绝不是第一个...)的语义更像是“移动从而使esp = ebp”。 - JUST MY correct OPINION
7
@zneak,你错了。movd实际上是一个MMX指令。如果你想要包含一个大小后缀(在这种情况下是可选的),你应该使用movl - bug
6
实际上,英特尔语法更为常见。我所知道的其他汇编语言都是先确定目标再确定源。你可以将其视为一种赋值操作。esp = ebp - phuclv
1
我很早就意识到,Intel X86汇编使用了我们曾经称之为逆波兰表示法的方法,这在商科专业人士中引起了很多困惑,他们习惯于代数中更像英语的从右到左的表示法,并且操作德州仪器计算器。相反,惠普计算器则迎合工程师的需求,使用逆波兰表示法。随着我开始学习使用各种汇编器,我很快发现大多数汇编器也使用逆波兰表示法。其中包括Univac Exec-8汇编和IBM BAL(基本汇编语言),它们用于IBM 360/370级大型机。 - David A. Gray
1
@DavidA.Gray:肯定不是逆波兰式,因为在逆波兰式中,操作数先于运算符,我不知道有哪种汇编语言会这样做。 - Ben Voigt

2
编译器使用这条指令在栈中释放函数占用的空间,leave指令与mov esp, ebppop ebp具有相同的行为。请注意保留HTML标签。

肯定 enterleave 不能 同时 用于释放堆栈上的已使用空间吧? - Pascal Cuoq
没错,就是这个“离开”指令,我犯了一个错误。 - kabab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接