函数调用的栈空间结构

  对函数调用过程的栈空间结构以前就知道,直到周二技术沙龙有同事提出不同看法,当时未能作答,这里分析一下。

测试代码如下:

int add(int a, int b)
{
    int i = a + b;
    return i;
}

int func(int a, int b)
{
    return add(3, 5);
}

int main()
{
    int a = func(3, 5);
    return 0;
}

linux下生成汇编代码如下:

add:
.LFB0:
    .cfi_startproc
    pushl   %ebp    ;保存ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp  ;esp指向栈底
    .cfi_def_cfa_register 5
    subl    $16, %esp  ;预留栈空间
    movl    12(%ebp), %eax
    movl    8(%ebp), %edx
    addl    %edx, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    leave    ;见汇编指令解释
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret     ;见汇编指令解释
    .cfi_endproc
.LFE0:
    .size   add, .-add
    .globl  func
    .type   func, @function
func:
.LFB1:
    .cfi_startproc
    pushl   %ebp  ;ebp入栈
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp  ;esp指向栈底
    .cfi_def_cfa_register 5
    subl    $8, %esp
    movl    $5, 4(%esp)
    movl    $3, (%esp)
    call    add    ;返回地址入栈,并跳转到add
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE1:
    .size   func, .-func
    .globl  main
    .type   main, @function

几条指令的汇编解释:

call:

  push eip

  jmp

leave:

  mov esp,ebp

  pop ebp

ret:

  pop eip

  add esp,4

pop eip:

  mov eip, [esp]

  add esp,4

栈空间结构图示:

————————————

ebp

local variable

5            ;func栈桢

3

返回地址

————————————

ebp  ;保存func的ebp

local variable

————————————

时间: 2024-12-16 10:17:31

函数调用的栈空间结构的相关文章

C语言函数调用及栈帧结构

source:http://blog.csdn.net/qq_29403077/article/details/53205010 一.地址空间与物理内存 (1)地址空间与物理内存是两个完全不同的概念,真正的代码及数据都存在物理内存中. 物理储存器是指实际存在的具体储存器芯片,CPU在操纵物理储存器的时候都把他们当做内存来对待,把他们看成由若干个储存单元组成的逻辑储存器,这个逻辑储存器就是我们所说的地址空间. 地址空间大小与逻辑储存器大小不一定相等. (2)进程的地址空间分布 进程的地址空间包括:

函数调用过程栈帧变化详解

http://www.cnblogs.com/fxplove/articles/2574451.html 数调用另一个词语表示叫作 过程.一个过程调用包括将数据和控制从代码的一部分传递到另一部分.另外,它还必须在进入时为过程的局部变量分配空间,并在推出时释放这些空间.而数据传递,局部变量的分配和释放通过操纵程序栈来实现.在了解本文章之前,您需要先对程序的进程空间有所了解,即对进程如何使用内存?如果你知道这些,下面的内容将是很easy的事情了.为了您的回顾还是将简单的分布图贴出来,便于您的回顾.

【.NET进阶】函数调用--函数栈

原文:http://www.cnblogs.com/rain-lei/p/3622057.html 函数调用大家都不陌生,调用者向被调用者传递一些参数,然后执行被调用者的代码,最后被调用者向调用者返回结果,还有大家比较熟悉的一句话,就是函数调用是在栈上发生的,那么在计算机内部到底是如何实现的呢? 对于程序,编译器会对其分配一段内存,在逻辑上可以分为代码段,数据段,堆,栈 代码段:保存程序文本,指令指针EIP就是指向代码段,可读可执行不可写 数据段:保存初始化的全局变量和静态变量,可读可写不可执行

赋值运算,拷贝运算,运算符重载,函数调用入栈,寄存器

赋值运算与拷贝运算的区别 如果对象在申明之后进行赋值运算,我们称之为赋值运算.例如:class1 A("af"); class1 B;B=A;此时实际调用的类的缺省赋值函数B.operator=(A); 如果对象在申明的同时马上进行初始化操作,则称之为拷贝运算.例如: class1 A("af"); class1 B=A; 此时其实际调用的是B(A)这样的浅拷贝操作. C++与C#对象的内存分配方式的不同 在C++中,对象的实例在编译的时候,就需要为其分配内存大小,

C函数调用与栈

这篇blog试图说明这么一个问题,当一个c函数被调用时,一个栈帧(stack frame)是如何被建立,又如何被消除的.这些细节跟操作系统平台及编译器的实现有关,下面的描述是针对运行在Linux的gcc编译器而言的.c语言的标准并没有描述实现的方式.所以,不同的编译器.不同的操作系统都可能有自己的建立栈帧的方式. 下面先看一个典型的栈帧: 上面个的这个图是一个典型的栈帧,图中,栈顶在上,地址空间往下增长. 在看看这个栈对应的函数代码: int foo(int arg1, int arg2, in

关于函数调用压栈和返回值问题的疑惑

按照C编译器的约定调用函数时压栈的顺序是从右向左,并且返回值是保存在eax寄存器当中.这个命题本该是成立的,下面用一个小程序来反汇编观察执行过程: #include<stdio.h> int add(int x, int y){ return x+y; } int main(){ int eax=0; int z =0; int x =6; int y =5; z=add(x,y); __asm__( "movl %%eax, %0" :"+b"(eax

函数调用的栈信息

/*1.栈在堆上面,栈的地址减少,堆的地址增加.2.方法的参数在栈上,参数是从右向左入栈,为什么? 主要是为了解决可变参数的问题,从右向左入栈,栈顶是第一个参数, 而第一个参数,指出了参数个数,或者推断出参数个数(printf 的格式化字符串). 从栈顶开始,可以遍历这些参数.3.pa本身也分配在栈上,pa的地址比a的地址小,pa的内容是a的地址4.ppa本身也分配在栈上,ppa的地址比pa的地址小,ppa的内容是pa的地址5.栈上数组tmp,相当于在栈上切出8个字节,tmp指向栈顶,地址最小,

C语言函数调用参数压栈的相关问题

参数入栈的顺序 以前在面试中被人问到这样的问题,函数调用的时候,参数入栈的顺序是从左向右,还是从右向左.当时没有想清楚,随口就说从右向左.其实这个回答是不完全正确的.因为其实入栈的顺序,不同的体系架构是不一样的,举例来说, 看下面的代码: #include <stdio.h> int test(int a, int b) { printf("address of a %x.\n", &a); printf("address of b %x.\n"

深入理解C语言的函数调用过程 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4240084.html 原文地址:深入理解C语言的函数调用过程 作者:wjlkoorey258 本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解.    先看一个最简单的程序: 点击(此处)折叠或打开 /*test.c*/ #include <stdio.h> int foo1(int m,int n,int p) { int x = m + n + p; ret