我现在正在学习程序集,对于(大概)标准函数模板,我一点也不了解。
因此,基于这本很好的书,“函数要记住的表单如下:”
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
复制相似问题