C语言之进程空间---进程空间、数据分布、函数压/出栈

一,进程空间与数据分布

程序,是经源码编译后的可编译文件,可执行文件可以多次被执行,比如我们可以多次打开某个应用。

进程,是程序加载到内存后开始执行、至执行结束,这样的一段时间概念,多次打开的应用,每打开一次都是一个进程,当我们关闭该应用时,该进程也就结束了。

程序是静态概念,而进程是动态/时间概念。
这里写图片描述

接下来,通过一个程序实例来说明:

include<stdio.h>
int a;     //a为全局变量且未初始化,位于bss区
static int b;    //b为静态变量且未初始化,位于bss区
int c=2;    //c为全局变量、已初始化为2且可读可写,位于rw区
static int d=4;    //d为静态变量、已初始化为4且可读可写,位于rw区
int main()
{
        int m=5;    //m为局部变量,位于stack区
        static int n=6;   
                    //n为静态变量、已初始化为6,且可读可写,位于rw区
        char *p="china";    //p为局部变量,位于stack区
        int array[10]={0,1,2,3,4,5,6,7,8,9};   
                              //array为数组,位于stack区
        int *q=(int *)malloc(100);    
                                 //malloc动态申请的空间位于heap区
        int fun();
}
int fun()
{
        int m;    //m为局部变量,位于stack区
        static int n;    //n为静态变量、且未初始化,位于bss区
        return 0;l
}

二,函数压栈与出栈

1,普通函数

以下面的代码为例,我来展示程序运行时进程空间的数据分布:

#include<stdio.h>
int m=10;
int fun(int a,int b);
int main()
{
     int i=4;
     int j=5;
     m=fun(i,j);
     return 0;
}
int fun(int a,int b)
{
        int c=0;
        c=a+b;
        return c;
}
cpu中有三个寄存器,分别为:
  • eip——指向代码区将要执行的指令,有两种移动方式,分别是“顺序”和“跳转”;
  • ebp——始终指向栈底;
  • esp——始终指向栈顶;
接下来,我将逐步以图文结合的方式来分析程序的运行过程:

1,初始状态时,程序尚未运行,栈空间为空、eip指向代码区的第一条指令——int main(),而ebp和esp则指向“内核设置的初始状态。如图所示:
这里写图片描述

2,程序开始执行main函数的第一条指令时,main函数在栈区建立“main函数栈空间。ebp的地址压栈——被保存到“main函数栈空间”以便结束后返回到初始状态。esp会移动到“main函数栈空间”的栈顶。而此时的ebp也会移动到“main函数栈空间”的栈底。eip指向下一条指令(int =4)。如图所示:
这里写图片描述

3,main函数栈空间中会开辟一个空间 i,赋值为4。ebp不移动。esp移动到栈顶。eip指向下一条指令(int j=5)。如图所示:
这里写图片描述

4,main函数栈空间中开辟一个空间 j ,赋值为5。ebp不移动。esp移动到栈顶。eip指向下一条指令( m=fun() )。如图所示:
这里写图片描述

5,此过程要传递两个参数。这两个参数均保存在“main函数栈空间”中。但却要被“fun函数栈空间”所使用。main函数栈空间中为两个参数a和b开辟空间。传参顺序与代码书写顺序正好相反。j 的值会传给a,而 i 的值会传给b。ebp不移动。esp移动到栈顶。如图所示:
这里写图片描述

6,此时,main函数栈空间会开辟一个空间来保存fun函数的返回值。然后,main函数栈空间再次开辟一个空间保存fun函数的返回地址,以便fun函数返回时能找到原来的位置。ebp不移动。esp移动到栈顶。如图所示:
这里写图片描述

7,eip跳转到fun函数的第一条指令( int fun() )。main函数栈空间开辟一个空间用来保存此时ebp的指向位置,即main函数栈空间的栈底地址。这样的话,当fun函数执行完、返回后,ebp能重新回到main函数栈空间的栈底。如图所示:
这里写图片描述

8,此时,开始构建fun函数栈空间。ebp移动到“fun函数栈空间”的栈底。实际上,由于此时栈内并没有数据,栈底与栈顶处于同一地址,ebp与esp指向重合。eip指向下一条指令(int c=0)。执行这一语句,fun函数栈空间会开辟一个空间C,值为0。ebp不移动。esp移动到栈顶。eip指向下一条指令( c=a+b )。如图所示:
这里写图片描述

9,此时,main函数栈空间中,a和b的值相加然后赋给C。C值变为9。ebp和esp均不移动。eip指向下一条指令( return 0 )。如图所示:
这里写图片描述

10,fun函数运行结束,其返回值会传到main函数栈空间的“保存fun函数返回值”的空间中,然后赋值给m。如图所示:
这里写图片描述

11,fun函数执行完毕。此时有三个任务:

ebp和esp重新指向main函数栈空间的栈底和栈顶,eip只想main函数中将要执行的指令。
fun函数返回到原来地址,继续执行main函数指令。
fun函数栈空间被回收释放

如图所示:
这里写图片描述

12,main函数返回后,程序执行结束。ebp和esp回到初始状态——内核设置的初始指向地址。main函数栈空间被清空。静态数据区清空。代码区也被清。程序执行结束!
这里写图片描述

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值