Linux 应用程序的地址空间分布

Linux 应用程序在被内核调入内存中运行后就成为一个进程,因此分析应用程序的地址空间实际上就是分析进程的地址空间分布。

应用程序的地址空间实际上由以下几个部分组成:代码段、初始化数据段、未初始化数据段(bss段)、堆、栈。其在内存中的分布如下:


     




APUE给出了各个段所包含内容的详细介绍,这里笔者用一个比较直观的方法验证各个段所包含的内容。

方法的思路是:编写一个含有各种数据的C程序,程序中打印出各个变量的地址,编译好以后让其在Linux中运行起来,接着通过查看进程的各个段的信息,进而得到,把打印出来的变量地址与进程各个段的地址区间比较,可以得出变量处在哪个段中。

下面是测试程序:

#include <stdio.h>
#include <malloc.h>

int global_init_a = 1; //全局、初始化
int global_uninit_a;   //全局、未初始化
static int global_static_init_a = 2;   //全局、静态、初始化
static int global_static_uninit_a;      //全局、静态、未初始化
const global_const_a = 3;      //全局、只读变量


int main(int argc, char *argv[])
{
    int local_init_a = 4;    //局部、初始化
    int local_uninit_a;     //局部、未初始化
    static int local_static_init_a = 5;   //局部、静态、初始化
    static int local_static_uninit_a;    //局部、静态、未初始化
    const local_const_a = 3;        //局部、常量
    
    int *p;
    p = (int*)malloc(sizeof(int));   //动态分配 
    
    printf("&global_init_a = %p,global_init_a = %d\n",&global_init_a, global_init_a);
    printf("&global_uninit_a = %p,global_uninit_a = %d\n",&global_uninit_a, global_uninit_a);
    printf("&global_static_init_a = %p,global_static_init_a = %d\n",&global_static_init_a, global_static_init_a);
    printf("&global_static_uninit_a = %p,global_static_uninit_a = %d\n",&global_static_uninit_a, global_static_uninit_a);
    printf("&global_const_a = %p,global_const_a = %d\n",&global_const_a, global_const_a);
    
    
    printf("&local_init_a = %p,localinit_a = %d\n",&global_init_a, global_init_a);
    printf("&local_uninit_a = %p,local_uninit_a = %d\n",&local_uninit_a, local_uninit_a);
    printf("&local_static_init_a = %p,local_static_init_a = %d\n",&local_static_init_a, local_static_init_a);
    printf("&local_static_uninit_a = %p,local_static_uninit_a = %d\n",&local_static_uninit_a, local_static_uninit_a);
    printf("&local_const_a = %p,local_const_a = %d\n",&local_const_a, local_const_a);   
    printf("p = %p\n",p); 
    while(1);
    return 0;	
}


将代码运行起来,得到如下信息:

 图 1


另开一个终端,输入命令: ps aux  、cat  /proc/17709/maps  查看进程信息如下:

图  2


从图 2 中可以看出各个段的区间为:

代码段:0x08048000 -- 0x08049000

数据段:0x08049000 -- 0x0804a000

堆(heap):0x094f3000 -- 0x09514000

栈(stack):0xbfd8f000 --  0xbfda4000

接着通过查看图 1中的各个变量的地址,可以看出其落在哪个区间,进而得出其实际上是处在哪个段。对比的过程省略,下面给出总结后的规律:

1.代码段:代码,全局常量(const)、字符串常量
2.数据段:全局变量(初始化以及未初始化的)、静态
变量(全局的和局部的、初始化的以及未初始化的)
3.堆:动态分配的区域

4.栈:局部变量(初始化以及未初始化的,但不包含静

态变量)、局部只读变量(const

这里还没有分析出bss段中的数据。可以使用命令: readelf -S app_maps_test 得出如下:



找到 .bss段,再将变量的地址带入,就可以看出哪种变量是存放在bss段的。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值