2019独角兽企业重金招聘Python工程师标准>>>

当发生函数调用的时候,栈空间中存放的数据是这样的:
1、调用者函数把被调函数所需要的参数按照与被调函数的形参顺序相反的顺序压入栈中,即:从右向左依次把被调函数所需要的参数压入栈;
2、调用者函数使用call指令调用被调函数,并把call指令的下一条指令的地址当成返回地址压入栈中(这个压栈操作隐含在call指令中);
3、在被调函数中,被调函数会先保存调用者函数的栈底地址(push ebp),然后再保存调用者函数的栈顶地址,即:当前被调函数的栈底地址(mov ebp,esp);
4、在被调函数中,从ebp的位置处开始存放被调函数中的局部变量和临时变量,并且这些变量的地址按照定义时的顺序依次减小,即:这些变量的地址是按照栈的延伸方向排列的,先定义的变量先入栈,后定义的变量后入栈;
所以,发生函数调用时,入栈的顺序为:
参数N
参数N-1
参数N-2
.....
参数3
参数2
参数1
函数返回地址
上一层调用函数的EBP/BP
局部变量1
局部变量2
....
局部变量N
函数调用栈如下图所示:


解释:
首先,将调用者函数的EBP入栈(push ebp),然后将调用者函数的栈顶指针ESP赋值给被调函数的EBP(作为被调函数的栈底,mov ebp,esp),此时,EBP寄存器处于一个非常重要的位置,该寄存器中存放着一个地址(原EBP入栈后的栈顶),以该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数的局部变量值,而该地址处又存放着上一层函数调用时的EBP值;
一般而言,SS:[ebp+4]处为被调函数的返回地址,SS:[EBP+8]处为传递给被调函数的第一个参数(最后一个入栈的参数,此处假设其占用4字节内存)的值,SS:[EBP-4]处为被调函数中的第一个局部变量,SS:[EBP]处为上一层EBP值;由于EBP中的地址处总是"上一层函数调用时的EBP值",而在每一层函数调用中,都能通过当时的EBP值"向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取被调函数的局部变量值";
如此递归,就形成了函数调用栈;
函数内局部变量布局示例:
#include <stdio.h>
#include <string.h>
struct C
{
  int a;
  int b;
  int c;
};
int test2(int x, int y, int z)
{
  printf("hello,test2\n");
  return 0;
}
int test(int x, int y, int z)
{
  int a = 1;
  int b = 2;
  int c = 3;
  struct C st;
  printf("addr x = %u\n",(unsigned int)(&x));
  printf("addr y = %u\n",(unsigned int)(&y));
  printf("addr z = %u\n",(unsigned int)(&z));
  printf("addr a = %u\n",(unsigned int)(&a));
  printf("addr b = %u\n",(unsigned int)(&b));
  printf("addr c = %u\n",(unsigned int)(&c));
  printf("addr st = %u\n",(unsigned int)(&st));
  printf("addr st.a = %u\n",(unsigned int)(&st.a));
  printf("addr st.b = %u\n",(unsigned int)(&st.b));
  printf("addr st.c = %u\n",(unsigned int)(&st.c));
  return 0;
}

int main(int argc, char** argv)
{
  int x = 1;
  int y = 2;
  int z = 3;
  test(x,y,z);
  printf("x = %d; y = %d; z = %d;\n", x,y,z);
  memset(&y, 0, 8);
  printf("x = %d; y = %d; z = %d;\n", x,y,z);
  return 0;
}
打印输出如下:
addr x = 4288282272
addr y = 4288282276
addr z = 4288282280
addr a = 4288282260
addr b = 4288282256
addr c = 4288282252
addr st = 4288282240
addr st.a = 4288282240
addr st.b = 4288282244
addr st.c = 4288282248
a = 1; b = 2; c = 3;
a = 0; b = 0; c = 3;
示例效果图:


该图中的局部变量都是在该示例中定义的;

这个图片中反映的是一个典型的函数调用栈的内存布局;

转载于:https://my.oschina.net/leeming/blog/92176

汇编语言---函数调用栈相关推荐

  1. C 语言 函数调用栈

    From:https://www.cnblogs.com/clover-toeic/p/3755401.html    https://www.cnblogs.com/clover-toeic/p/3 ...

  2. C语言和汇编语言函数调用

    C语言和汇编语言函数调用关系 1.汇编语言函数调用 X86结构中,cs寄存器和rip寄存器共同控制着CPU要执行的下一条指令(当前在不同的模式中控制方式不同,如:实地址2模式和保护模式,长模式等),一 ...

  3. C语言函数调用栈(一)

    以下全文转载自:C语言函数调用栈(一) 程序的执行过程可看作连续的函数调用.当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行.函数调用过程通常使用堆栈实现,每个用户态 ...

  4. 关于ceph源码 backtrace 打印函数调用栈

    当集中精力看一个问题的时候,时间久了就会有这样一个状态,天空飘来五个字,那都不算事 ceph源码庞大的体量以及复杂的设计让很多人望而却步,尤其是大量的纯虚函数更是让读者迷失在代码的海洋,这个时候函数调 ...

  5. 如何在系统崩溃时从C++中获取函数调用栈信息?

    这篇文章主要讲述在 Linux 和 Windows 这 2 个平台上,如何用C++ 来捕获函数调用栈里的信息. 一.前言 程序在执行过程中 crash 是非常严重的问题,一般都应该在测试阶段排除掉这些 ...

  6. 一、 函数调用栈,执行上下文及变量对象

    前言 为什么会有这篇文章? 在书籍或博客上,我们经常会看到「作用域链」.「闭包」.「变量提升」等概念,说明一个问题 -- 它们很重要. 但很多时候,对于这些概念,看的时候觉得自己已经明白了,可过不了多 ...

  7. 函数调用栈的获取原理分析【转】

    转自:http://hutaow.com/blog/2013/10/15/dump-stack/ 上一篇文章<在Linux程序中输出函数调用栈>,讲述了在Linux中如何利用backtra ...

  8. python查看函数调用栈

    我在看开源框架代码的时候,有时候好几天都无法找到一个函数被调用的具体位置..这个时候就需要记录一下函数调用栈. 源码如下 def Caller(func):def f(*args,**kwargs): ...

  9. 在Linux程序中输出函数调用栈

    程序发生异常时,将函数的调用栈打印出来,可以大大提高定位效率. Linux中提供了三个函数用来获取调用栈: /* 获取函数调用栈 */ int backtrace(void **buffer, int ...

最新文章

  1. printf(%d, -10u); 这个输出什么呀, 0或1?
  2. docker 安装 oracle12,使用Docker安装Oracle 12c
  3. 如何建立顺畅的项目流程
  4. vue项目持久化存储数据的实现代码
  5. cv2.dnn.readNetFromDarknet()在python3上遇到的问题
  6. 作为一个新手程序员该如何成长?
  7. 学习心得_【数字建行大学学习心得】第二期
  8. fseek函数与ftell函数使用例程
  9. java中double类型占几个字节_Java中的单双精度数据类型分别占几个字节?
  10. 计算机系统结构与组成原理
  11. Java版PageRank及网站收录情况查询代码
  12. debian7开机启动
  13. H指数(h-index)的Python实现
  14. java ?: 三目运算符
  15. 计算机桌面24小时制设置,时间怎么设置24小时
  16. C# 操作Excel数据透视表详解 – 创建、操作和删除
  17. 2013年第十九届全国青少年信息学奥林匹克联赛初赛
  18. Android期末总结
  19. Redis主从复制、Redis哨兵模式、Redis集群
  20. CSDN微软俱乐部成立

热门文章

  1. java 数组构造_java – 从数组构造(非二进制)树
  2. PHP爱讯云商城源码v0.7.0-新增app功能
  3. 玛塔留言板无刷新留言板程序
  4. WCF必知必会以及与Webapi的区别
  5. ASP.Net 附加调试,aspnet_wp.exe进程不能启动解决办法 .
  6. (一)KitJs瀑布流组件特点
  7. ConcurrentDictionary:.NET 4.0中新的线程安全的哈希表
  8. Magento: 获取类别所有子类别 (无限级别-目录树) Get All Sub Categories
  9. Magento教程 19:客户评论的审核与发布! (Pending Reviews)
  10. 人工智障学习笔记——机器学习(11)PCA降维