我知道这是一个非常基本的问题,但在这里:
我开始学习汇编程序,我正在努力了解堆栈的工作原理。
首先,当我将值传递给汇编程序函数时,我会像这样访问它:
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再次执行此操作有什么好处?
有没有人有一个关于如何学习堆栈如何工作的好学习工具(对于dummies-type)的提示,这样可以学习这些堆栈指针,返回地址等等?我没有找到任何关于它如何工作的良好视觉演示。 谢谢!
答案 0 :(得分:2)
在大多数情况下使用%ebp有历史原因:在16位程序中,如" movw 2(%sp),%ax" x86 CPU不支持,因为x86 CPU仅支持%bx,%si,%di和%bp寄存器用于内存寻址。所以在16位程序中你不能使用%sp,所以你改用%bp。
使用优化良好的现代编译器时,您将看不到" push"和" mov%esp,%ebp" 32位代码中的指令,但代码看起来就像你的第一个例子(" 4(%esp)"而不是" 8(%ebp)")。
此类编译器有时会将%ebp寄存器用于不同目的。
有一个用例仍然需要%ebp:alloca()函数:此函数通过执行" sub%eax,%esp"来保留堆栈中的内存。 (或类似的)指令。在这条指令之后,你不再知道你的论点在哪里。
但是在32位代码中使用" flat"内存布局(%ds =%ss)您也可以使用任何其他寄存器而不是%ebp。
答案 1 :(得分:1)
差异和原因都与堆栈帧有关。以下链接有一个相当不错的摘要(如果我自己这么说)。