概述
void swap(int * a, int *b)
{
int c;
c = *a; *a = *b; *b = c;
}
int main()
{
int a, b;
a = 16; b = 32;
swap(&a, &b);
return (a - b);
}
.text
_swap:
pushl %ebp # 保存原ebp值,设置当前函数的帧指针。
movl %esp,%ebp
subl $4,%esp # 为局部变量c在栈内分配空间。
movl 8(%ebp),%eax # 取函数第1个参数,该参数是一个整数类型值的指针。
movl (%eax),%ecx # 取该指针所指位置的内容,并保存到局部变量c中。
movl %ecx,-4(%ebp)
movl 8(%ebp),%eax # 再次取第1个参数,然后取第2个参数。
movl 12(%ebp),%edx
movl (%edx),%ecx # 把第2个参数所指内容放到第1个参数所指的位置。
movl %ecx,(%eax)
movl 12(%ebp),%eax # 再次取第2个参数。
movl -4(%ebp),%ecx # 然后把局部变量c中的内容放到这个指针所指位置处。
movl %ecx,(%eax)
leave # 恢复原ebp、esp值(即movl %ebp,%esp; popl %ebp;)。
ret
_main:
pushl %ebp # 保存原ebp值,设置当前函数的帧指针。
movl %esp,%ebp
subl $8,%esp # 为整型局部变量a和b在栈中分配空间。
movl $16,-4(%ebp) # 为局部变量赋初值(a=16,b=32)。
movl $32,-8(%ebp)
leal -8(%ebp),%eax # 为调用swap()函数作准备,取局部变量b的地址,
pushl %eax # 作为调用的参数并压入栈中。即先压入第2个参数。
leal -4(%ebp),%eax # 再取局部变量a的地址,作为第1个参数入栈。
pushl %eax
call _swap # 调用函数swap()。
movl -4(%ebp),%eax # 取第1个局部变量a的值,减去第2个变量b的值。
subl -8(%ebp),%eax
leave # 恢复原ebp、esp值(即movl %ebp,%esp; popl %ebp;)。
ret
before call:准备实参压入栈,
call 指令:
压入返回值(函数调用结束后执行的下一条语句地址)
执行call ( eip 入栈 jump )
Callee execution(被调用者执行):
保存旧ebp,没更新ebp、esp。
分配临时变量内存
leave指令:
恢复原ebp、esp值
ret指令:
取栈顶值作为eip (这时候栈顶的值是函数调用结束需要执行的下一条指令地址)
总结下:
每次进行函数调用就是创建一个新栈帧保存旧栈帧,还有就是通过EIP进行跳转到被调用的代码,和返回调用出继续执行。
被调用者的栈帧就是保存函数局部变量,和恢复到调用者栈帧执行环境的必要信息。
帧,还有就是通过EIP进行跳转到被调用的代码,和返回调用出继续执行。
被调用者的栈帧就是保存函数局部变量,和恢复到调用者栈帧执行环境的必要信息。
最后
以上就是危机山水为你收集整理的函数调用栈的全部内容,希望文章能够帮你解决函数调用栈所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复