摘要:通过编写一个例程addr.c,总结分析了linux应用程序的地址布局,包括代码段,数据段,BSS段,堆(heap)和栈(stack)的分布,分析了程序在运行之后,各个变量常量动态申请分配的内存分别在什么位置。
一、程序的构成及内存分布
linux应用程序的构成包括:代码段,数据段,BSS段(未初始化数据段),堆和栈。
上面组成部分当程序在linux中运行的时候,分布情况如下:
从下到上依次是代码段,数据段,BSS段,堆和栈,其中代码段的起始地址固定为0x08048000,栈按照自上向下生长,堆按照自下向上生长。
二、数据存放的位置
1.代码段:代码,全局常量const,字符串常量。
2.数据段:全局变量,静态变量。
3.堆:动态分配的区域
4.栈:局部变量,局部只读变量
总之,凡事被static修饰的变量,全部放在数据段,无论是全局变量还是局部变量。
三、分析addr.c查看数据存放位置
这里我写的addr.c函数如下:
<span style="font-size:18px;">#include<stdio.h>
#include<malloc.h>
int g_a;
int g_b=0;
static int s_g_a;
static int s_g_b=0;
const int c_g_b=0;
int main(void)
{
intl_a;
intl_b=0;
staticint s_l_a;
staticint s_l_b=0;
constint c_l_b=0;
int*m_l_a;
m_l_a=malloc(sizeof(int));
printf("1-g_aaddress is:%0x,g_a is:%d\n",&g_a,g_a);
printf("2-g_baddress is:%0x,g_b is:%d\n",&g_b,g_b);
printf("3-s_g_aaddress is:%0x,s_g_a is:%d\n",&s_g_a,s_g_a);
printf("4-s_g_baddress is:%0x,s_g_b is:%d\n",&s_g_b,s_g_b);
printf("5-c_g_baddress is:%0x,c_g_b is:%d\n",&c_g_b,c_g_b);
printf("6-l_aaddress is:%0x,l_a is:%d\n",&l_a,l_a);
printf("7-l_baddress is:%0x,l_b is:%d\n",&l_b,l_b);
printf("8-s_l_aaddress is:%0x,s_l_a is:%d\n",&s_l_a,s_l_a);
printf("9-s_l_baddress is:%0x,s_l_b is:%d\n",&s_l_b,s_l_b);
printf("10-c_l_baddress is:%0x,c_l_b is:%d\n",&c_l_b,c_l_b);
printf("11-m_l_aaddress is:%0x,m_l_a is:%d\n",m_l_a,*m_l_a);
while(1);
return0;
}</span>
主要是查看不同的变量,包括全局未初始化,全局初始化,静态全局未初始化,静态全局初始化,局部未初始化,局部初始化,静态局部未初始化,静态局部初始化和动态分配的内存。
按照下面的指令操作:
#gcc addr.c –o addr
#./addr
运行起来之后,重新打开一个终端,然后:
# ps aux |grep ./addr
这时候就找到addr这个进程运行的pid号,我的如下;
这里是12501,然后接着输入:
# cat /proc/12501/maps
这时候我要的信息就出来了:
下面我做了一张表格,把这个maps和我们刚才的变量对应起来:
名称 | 地址范围 | 包含变量 |
代码段 | 08048000-08049000 | c_g_b |
数据段 | 08049000-0804a000 | g_a,g_b,s_g_a,s_g_b,s_l_a,s_l_b |
堆 | 090d4000-b78fe000 | m_l_a |
栈 | bfc8a000-bfcab000 | l_a,l_b,c_l_b |
BSS段 | 0804995c-0804997c | g_a,g_b,s_g_a,s_g_b,s_l_a,s_l_b |
这里和我们刚才总结的是一样的吧,最后的BSS段是因为要借助另一个方法来查看,输入:
# readelf –S addr
我的出现如下信息:
可以看到bss的信息了吧,往上面的表里面填,这里给了一个起始地址,一相对数据段起始地址的偏移量和这段的大小,大小为多少呢,20,结束地址我们也可以计算得到,往里面填进去,可以完整的得到上表。
这里为什么BSS段和数据段包含的变量都重合了呢?难道数据段里面的东西都包含在了BSS段吗?显然不是的!!!因为我的程序即使初始化了,也给的是0,程序默认是没有进行初始化的,我们的BSS段就是数据段里面未初始化的数据存放的地方,不信你可以把g_b初始化的时候改为1,再按照以上方法,BSS段里面就没有g_b了,我反复做过几次这个实验验证自己的想法,一开始也因为这个卡了一会儿,不得不说自己做一遍,理解真的会加深很多。
这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!