我是靠谱客的博主 危机山水,最近开发中收集的这篇文章主要介绍函数调用栈,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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进行跳转到被调用的代码,和返回调用出继续执行。

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

最后

以上就是危机山水为你收集整理的函数调用栈的全部内容,希望文章能够帮你解决函数调用栈所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部