C语言之进程空间---进程空间、数据分布、函数压/出栈
2018-01-29 04:17
357 查看
一,进程空间与数据分布
程序,是经源码编译后的可编译文件,可执行文件可以多次被执行,比如我们可以多次打开某个应用。进程,是程序加载到内存后开始执行、至执行结束,这样的一段时间概念,多次打开的应用,每打开一次都是一个进程,当我们关闭该应用时,该进程也就结束了。
程序是静态概念,而进程是动态/时间概念。
接下来,通过一个程序实例来说明:
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函数栈空间被清空。静态数据区清空。代码区也被清。程序执行结束!
相关文章推荐
- matlab 函数或者GUI从工作空间读取参数数据
- c语言中函数(linux命令查看依赖类库),数组(内存存储是连续的内存空间),Linux下查看&a,&a[0],a之间的值,可变数组
- Linux中使用C语言的fork()函数创建子进程的实例教程
- 实现基本工作空间和函数之间数据的相互调用
- 程序员之---C语言细节22(函数返回指针注意事项<悬空指针>、查看进程能够分配的内存大小)
- SQL Servr 2008空间数据应用系列四:基础空间对象与函数应用 推荐
- bug fixed 系列之二 : 进程内存空间分布情况
- C语言sendto()函数:经socket传送数据
- Android For JNI(二)——C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器
- C语言中free函数如何确定释放的空间大小
- C语言fprintf()函数:输出函数(格式化输出数据至文件)
- 进程虚拟地址空间之数据分区存放
- SQL Server 2008空间数据应用系列四:基础空间对象与函数应用
- 如何用C语言产生10000个不重复的随机整数?并且把它写入到一个文本文件中作为其他函数测试用的数据。
- Db2 使数据均匀地分布在不同表空间不一定能加快备份速度
- Android For JNI(二)——C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器
- linux进程空间地址分布
- C语言中获取进程识别码的相关函数
- C语言calloc()函数:分配内存空间并初始化
- 举例讲解C语言的fork()函数创建子进程的用法