汇编函数返回后%esp指向何处?为何需执行addl $8,%esp?
关于ret指令后%esp位置与调用者栈清理的疑问解答
你的核心误解在于对调用约定中栈参数清理责任的忽略,以及对"函数调用前的位置"的定义偏差:
先明确调用
power函数时的完整栈流程(以传入两个4字节参数为例):- 调用者先压入第二个参数:
pushl %ebx(假设是底数) - 再压入第一个参数:
pushl %eax(假设是指数) - 执行
call power:此时CPU将当前%eip压入栈,%esp减少4字节,跳转到power入口
- 调用者先压入第二个参数:
power函数的收尾流程你理解的部分是正确的:movl %ebp, %esp:把%esp拉回栈帧基址,清理局部变量占用的栈空间popl %ebp:恢复调用前的%ebp,%esp增加4字节ret:弹出栈顶的返回地址到%eip,%esp再增加4字节
关键差异点:
ret执行后,%esp的位置是调用者压入两个参数之后、执行call之前的位置,而不是调用者还没压参数时的初始位置。因为压入的两个参数(共8字节)还留在栈上,所以调用者需要执行addl $8, %esp来跳过这两个参数,让%esp回到调用函数前(未压入参数)的状态。
本质上,ret只负责处理call指令压入的返回地址,栈上的函数参数需要调用者自己清理——这是Cdecl调用约定的规则,也是你看到addl $8, %esp的原因。
内容的提问来源于stack exchange,提问作者trozzel
相关产品推荐
相关产品推荐

