我现在正在学习程序集,对于(大概)标准函数模板,我一点也不了解。
因此,基于这本很好的书,“函数要记住的表单如下:”
function_label:
pushl %ebp
movl %esp, %ebp
< normal function code goes here>
movl %ebp, %esp
popl %ebp
ret
好吧,我对此很满意,但有一件事我不明白。在“正常函数代码”之后,我们恢复esp
的初始(预调用)值,该值以前存储在ebp
中。
现在,我清楚地理解了为什么我们要将esp
值服务回调用上下文。我不明白的是,在什么条件下,esp
值可以在函数的执行过程中被更改。
这是否是针对我们自己的某种保护(万一我们在代码中的某个地方破坏了堆栈)?或者,在函数中更改堆栈值是正常的做法?或者,即使我们不对其进行任何操作,初始esp
值也可能在执行过程中发生更改?(事实上,我不知道这是怎么回事。)
在考虑这个问题时,我觉得很傻,并在这段简单的代码中用gdb
检查了gdb
值:
.section .data
message:
.asciz "> Hello from function #%d\n"
.section .text
.globl main
main:
nop
call overhere
pushl $0
call exit
overhere:
pushl %ebp
movl %esp, %ebp
pushl $1
pushl $message
call printf
add $8, %esp
movl %ebp, %esp
popl %ebp
ret
而esp
(正如我所预期的)没有受到影响,因此将ebp
迁移到esp
并没有真正改变任何事情。
现在,我希望我想弄清楚的是:
esp
值本身会发生变化吗?(我敢打赌它做不到。)esp
值是一个错误吗?先谢谢你原谅我的无知。
发布于 2014-11-22 15:26:31
我感到困惑的是,您为什么忽略了显式更改esp
:add $8, %esp
的指令。所以答案显然是肯定的,它可能在一个函数的过程中发生变化,而不是一个错误。注意,push
和call
也改变了它,实际上add
是为了补偿两个push
指令( printf
末尾的ret
将平衡call
)。更改esp
的另一个典型原因是局部变量的分配。在您显示的函数模板中省略了这一点,它通常看起来就像sub $size_of_locals, %esp
后面的movl %esp, %ebp
。
也就是说,您不需要使用ebp
来记住堆栈指针,只要您确保它在函数出口处的值与输入时的值相同。最近版本的gcc在启用优化时不使用ebp
,否则可以使用-fomit-frame-pointer
进行优化。
https://stackoverflow.com/questions/27078970
复制相似问题