当前位置:七道奇文章资讯系统安全Linux安全
日期:2012-04-14 04:47:00  来源:本站整理

Linux下C程序进程地址空间筹划[Linux安全]

赞助商链接



  本文“Linux下C程序进程地址空间筹划[Linux安全]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:

  我们在学习C程序开辟经常常会碰到一些概念:代码段、数据段、BSS段(Block Started by Symbol) 、堆(heap)和栈(stack).先看一张教材上的表示图(根源,《UNIX环境高级编程》一书),显示了进程地址空间中典型的存储区域分配情形.

  从图中可以看出:

  从低地址到高地址辨别为:代码段、(初始化)数据段、(未初始化)数据段(BSS)、堆、栈、号令行参数和环境变量堆向高内存地址生长栈向低内存地址生长

  还常常看到下面这个图(根源,不详):

  先看一段程序.

#include #include int global_init_a=1; int global_uninit_a; static int static_global_init_a=1; static int static_global_uninit_a; const int const_global_a=1; int global_init_b=1; int global_uninit_b; static int static_global_init_b=1; static int static_global_uninit_b; const int const_global_b=1; /*上面全部为全局变量,main函数中的为部分变量*/ int main() int local_init_a=1; int local_uninit_a; static int static_local_init_a=1; static int static_local_uninit_a; const int const_local_a=1; int local_init_b=1; int local_uninit_b; static int static_local_init_b=1; static int static_local_uninit_b; const int const_local_b=1; int * malloc_p_a; malloc_p_a=malloc(sizeof(int)); printf(" &global_init_a=%p global_init_a=%d ",&global_init_a,global_init_a); printf(" &global_uninit_a=%p global_uninit_a=%d ",&global_uninit_a,global_uninit_a); printf(" &static_global_init_a=%p static_global_init_a=%d ",&static_global_init_a,static_global_init_a); printf("&static_global_uninit_a=%p static_global_uninit_a=%d ",&static_global_uninit_a,static_global_uninit_a); printf(" &const_global_a=%p const_global_a=%d ",&const_global_a,const_global_a); printf(" &global_init_b=%p global_init_b=%d ",&global_init_b,global_init_b); printf(" &global_uninit_b=%p global_uninit_b=%d ",&global_uninit_b,global_uninit_b); printf(" &static_global_init_b=%p static_global_init_b=%d ",&static_global_init_b,static_global_init_b); printf("&static_global_uninit_b=%p static_global_uninit_b=%d ",&static_global_uninit_b,static_global_uninit_b); printf(" &const_global_b=%p const_global_b=%d ",&const_global_b,const_global_b); printf(" &local_init_a=%p local_init_a=%d ",&local_init_a,local_init_a); printf(" &local_uninit_a=%p local_uninit_a=%d ",&local_uninit_a,local_uninit_a); printf(" &static_local_init_a=%p static_local_init_a=%d ",&static_local_init_a,static_local_init_a); printf(" &static_local_uninit_a=%p static_local_uninit_a=%d ",&static_local_uninit_a,static_local_uninit_a); printf(" &const_local_a=%p const_local_a=%d ",&const_local_a,const_local_a); printf(" &local_init_b=%p local_init_b=%d ",&local_init_b,local_init_b); printf(" &local_uninit_b=%p local_uninit_b=%d ",&local_uninit_b,local_uninit_b); printf(" &static_local_init_b=%p static_local_init_b=%d ",&static_local_init_b,static_local_init_b); printf(" &static_local_uninit_b=%p static_local_uninit_b=%d ",&static_local_uninit_b,static_local_uninit_b); printf(" &const_local_b=%p const_local_b=%d ",&const_local_b,const_local_b); printf(" malloc_p_a=%p *malloc_p_a=%d ",malloc_p_a,*malloc_p_a); return 0; 下面是输出后果.

  先细心解析一下上面的输出后果,看看能得出什么结论.貌似很难解析出来什么后果.好了我们持续往下看吧.

  接下来,通过查看proc文件系统下的文件,看一下这个进程的真实内存分配情形.(我们需求在程序完毕前加一个死循环,不让进程完毕,以便我们进一步解析).

  在return 0前,增添 while(1); 语句

  重新编译后,运路程序,程序将进入死循环.

  利用ps号令查看一下进程的pid

  #ps -aux | grep a.out

  查看/proc/2699/maps文件,这个文件显示了进程在内存空间中各个区域的分配情形.

  #cat /proc/2699/maps

  上面红颜色标出的几个区间是我们感爱好的区间:

  08048000-08049000 r-xp 貌似是代码段08049000-0804a000 r--p 暂时不清楚,看不出来0804a000-0804b000 rw-p 貌似为数据段08a7e000-08a9f000 rw-p 堆bff73000-bff88000 rw-p 栈

  我们把这些数据与最后一次的程序运行后果举行对比,看看有什么结论.

  &global_init_a=0x804a018 全局初始化:数据段 global_init_a=1

  &global_uninit_a=0x804a04c 全局未初始化:数据段 global_uninit_a=0

  &static_global_init_a=0x804a01c 全局静态初始化:数据段 static_global_init_a=1

  &static_global_uninit_a=0x804a038 全局静态未初始化:数据段 static_global_uninit_a=0

  &const_global_a=0x80487c0 全局只读变量: 代码段 const_global_a=1

  &global_init_b=0x804a020 全局初始化:数据段 global_init_b=1

  &global_uninit_b=0x804a048 全局未初始化:数据段 global_uninit_b=0

  &static_global_init_b=0x804a024 全局静态初始化:数据段 static_global_init_b=1

  &static_global_uninit_b=0x804a03c 全局静态未初始化:数据段 static_global_uninit_b=0

  &const_global_b=0x80487c4 全局只读变量: 代码段 const_global_b=1

  &local_init_a=0xbff8600c 部分初始化:栈 local_init_a=1

  &local_uninit_a=0xbff86008 部分未初始化:栈 local_uninit_a=134514459

  &static_local_init_a=0x804a028 部分静态初始化:数据段 static_local_init_a=1

  &static_local_uninit_a=0x804a040 部分静态未初始化:数据段 static_local_uninit_a=0

  &const_local_a=0xbff86004 部分只读变量:栈 const_local_a=1

  &local_init_b=0xbff86000 部分初始化:栈 local_init_b=1

  &local_uninit_b=0xbff85ffc 部分未初始化:栈 local_uninit_b=-1074241512

  &static_local_init_b=0x804a02c 部分静态初始化:数据段 static_local_init_b=1

  &static_local_uninit_b=0x804a044 部分静态未初始化:数据段 static_local_uninit_b=0

  &const_local_b=0xbff85ff8 部分只读变量:栈 const_local_b=1

  p_chars=0x80487c8 字符串常量:代码段 p_chars=abcdef

  malloc_p_a=0x8a7e008 malloc动态分配:堆 *malloc_p_a=0

  通过以上解析我们暂时可以得到的结论以下,在进程的地址空间中:

  数据段中存放:全局变量(初始化以及未初始化的)、静态变量(全局的和部分的、初始化的以及未初始化的)

  代码段中存放:全局只读变量(const)、字符串常量

  堆中存放:动态分配的区域

  栈中存放:部分变量(初始化以及未初始化的,但不包含静态变量)、部分只读变量(const)

  这里我们没有发现BSS段,但是我们将未初始化的数据按照地址举行排序看一下,可以发现一个规律.

  &global_init_a=0x804a018 全局初始化:数据段 global_init_a=1

  &static_global_init_a=0x804a01c 全局静态初始化:数据段 static_global_init_a=1

  &global_init_b=0x804a020 全局初始化:数据段 global_init_b=1

  &static_global_init_b=0x804a024 全局静态初始化:数据段 static_global_init_b=1

  &static_local_init_a=0x804a028 部分静态初始化:数据段 static_local_init_a=1

  &static_local_init_b=0x804a02c 部分静态初始化:数据段 static_local_init_b=1

  &static_global_uninit_a=0x804a038 全局静态未初始化:数据段 static_global_uninit_a=0

  &static_global_uninit_b=0x804a03c 全局静态未初始化:数据段 static_global_uninit_b=0

  &static_local_uninit_a=0x804a040 部分静态未初始化:数据段 static_local_uninit_a=0

  &static_local_uninit_b=0x804a044 部分静态未初始化:数据段 static_local_uninit_b=0

  &global_uninit_b=0x804a048 全局未初始化:数据段 global_uninit_b=0

  &global_uninit_a=0x804a04c 全局未初始化:数据段 global_uninit_a=0

  这里可以发现,初始化的和未初始化的数据仿佛是脱离存放的,因此我们可以猜想BSS段是存在的,只不过数据段是分为初始化和未初始化(即BSS段)的两部份,他们在加载到进程地址空间时是归并为数据段了,在进程地址空间中没有单独分为一个区域.

  还有一个问题,静态数据与非静态数据能否是脱离存放的呢?请读者自行解析一下.

  接下来我们从程序的角度看一下,这些存储区域是若何分配的.首先我们先介绍一下ELF文件格局.

  ELF(Executable and Linkable Format )文件格局是一个开放尺度,各种UNIX系统的可履行文件都采取ELF格局,它有三种差别的范例:–可重定位的目标文件(Relocatable,大概 Object File)–可履行文件(Executable)–同享库(Shared Object,大概Shared Library)下图为ELF文件的构造表示图(根源,不详):

  一个程序编译生成目标代码文件(ELF文件)的历程以下,此图引自《程序员的自我涵养》一书的一个图:

  可以通过readelf号令查看EFL文件的相关信息,比方 readelf -a a.out ,我们只关心各个段的分配情形,因此我们利用以下号令:

# readelf -S a.out 

  将这里的内存筹划与之前看到的程序的运行后果举行解析:

  &global_init_a=0x804a018 全局初始化:数据段 global_init_a=1

  &global_uninit_a=0x804a04c 全局未初始化:BSS段 global_uninit_a=0

  &static_global_init_a=0x804a01c 全局静态初始化:数据段 static_global_init_a=1

  &static_global_uninit_a=0x804a038 全局静态未初始化:BSS段 static_global_uninit_a
  以上是“Linux下C程序进程地址空间筹划[Linux安全]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:

  • windows下的近似linux下的grep号令--findstr
  • linux下mysql链接被防火墙禁止的办理办法
  • Linux下mysql新建账号及权限设置办法
  • SUSE Linux下搭建Web服务器
  • Windows/Linux MySQL忘掉密码重置密码教程
  • Linux下Apache自动监测重启脚本(智能化程度较高)
  • linux备份 linux克隆 linux clone
  • <b>为什么 Linux不需求碎片整理</b>
  • CentOS6 yum搭建Linux+Nginx+PHP+MYSQL(LNMP)
  • Linux系统有效防备ARP攻击
  • Linux下 Memcache的安装和简单管理
  • 笔记本预装linux重装成windows系统
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .