函数调用栈

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

img

before call:准备实参压入栈,

call 指令:

​ 压入返回值(函数调用结束后执行的下一条语句地址)

​ 执行call ( eip 入栈 jump )

Callee execution(被调用者执行):

​ 保存旧ebp,没更新ebp、esp。

​ 分配临时变量内存

leave指令:

​ 恢复原ebp、esp值

ret指令:

​ 取栈顶值作为eip (这时候栈顶的值是函数调用结束需要执行的下一条指令地址)

总结下:

每次进行函数调用就是创建一个新栈帧保存旧栈帧,还有就是通过EIP进行跳转到被调用的代码,和返回调用出继续执行。

被调用者的栈帧就是保存函数局部变量,和恢复到调用者栈帧执行环境的必要信息。

帧,还有就是通过EIP进行跳转到被调用的代码,和返回调用出继续执行。

被调用者的栈帧就是保存函数局部变量,和恢复到调用者栈帧执行环境的必要信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值