一个Linux C进程内存布局的验证程序的分析

测试代码为:
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 int global_init_val=100;//初始化后的全局变量
  4 int global_noninit_val;//未初始化的全局变量
  5 extern char **environ;//定义全局的指针变量接收系统环境变量
  6 int main(int argc,char *argv[],char* envp[])
  7 {
  8         static int localstaticval=10;//初始化了的静态局部变量
             int i=23;//初始化的局部动态变量
  9         char * localval;//局部动态变量
 10         localval = malloc(10);//申请分配内存,将首指针赋给局部变量
 11         printf("address of text  is:%p\n",main);
 12         printf("address of data  is:%p,%p\n",&global_init_val,&localstaticval); 
 13         printf("address of bss   is:%p\n",&global_noninit_val);
 14         printf("address of heap  is:%p\n",localval);
 15         printf("address of stack is:%p\n",&localval);
 16         free(localval);//释放动态分配的内存空间,如不释放,会造成内存泄露
 17         printf("&environ =%p,environ = %p\n",&envp,envp);
 18         printf("&argv=%p,argv=%p\n",&argv,argv);
 19         return 0;
 20 }
编辑makefie如下
memlayout:memlayout.o
        gcc memlayout.o -o memlayout
memlayout.o:memlayout.c
        gcc -c memlayout.c
输入make命令
gcc -c memlayout.c
gcc memlayout.o -o memlayout
生成的目标文件和可执行文件可进行readelf操作,有利于进一步弄清楚程序的内存空间布局。
接着执行./memlayout命令执行程序,输出结果如下:
address of text  is:0x8048454
address of data  is:0x804a01c,0x804a020
address of bss   is:0x804a02c
address of i         is:0xbff4af3c
address of data  is:0x804a01c,0x804a020
address of heap  is:0x9a5d008
address of stack is:0xbff4af38
&environ =0xbff4af58,environ = 0xbff4affc
&argv=0xbff4af54,argv=0xbff4aff4

按照已有的知识,从低地址到高地址依次为.text段、.data段、.bss段、.heap段、.stack段,最高地址处为命令行参数和环境变量。
各段的相对位置是确定的,但是各段的绝对起始位置是否就是上述输出结果呢?

为了搞清楚这个,我对目标文件进行readelf操作,执行命令:readelf -a memlayout.o
接着执行readelf -a memlayout,截取我们关心的部分:
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048134 000134 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048148 000148 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048168 000168 000024 00   A  0   0  4
  [ 4] .hash             HASH            0804818c 00018c 000030 04   A  6   0  4
  [ 5] .gnu.hash         GNU_HASH        080481bc 0001bc 000020 04   A  6   0  4
  [ 6] .dynsym           DYNSYM          080481dc 0001dc 000070 10   A  7   1  4
  [ 7] .dynstr           STRTAB          0804824c 00024c 000058 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          080482a4 0002a4 00000e 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         080482b4 0002b4 000020 00   A  7   1  4
  [10] .rel.dyn          REL             080482d4 0002d4 000008 08   A  6   0  4
  [11] .rel.plt          REL             080482dc 0002dc 000028 08   A  6  13  4
  [12] .init             PROGBITS        08048304 000304 000030 00  AX  0   0  4
  [13] .plt              PROGBITS        08048334 000334 000060 04  AX  0   0  4
  [14] .text             PROGBITS        080483a0 0003a0 00026c 00  AX  0   0 16
  [15] .fini             PROGBITS        0804860c 00060c 00001c 00  AX  0   0  4
  [16] .rodata           PROGBITS        08048628 000628 0000c8 00   A  0   0  4
  [17] .eh_frame         PROGBITS        080486f0 0006f0 000004 00   A  0   0  4
  [18] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  7   0  4
  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049ff4 000ff4 000020 04  WA  0   0  4
  [24] .data             PROGBITS        0804a014 001014 000010 00  WA  0   0  4
  [25] .bss              NOBITS          0804a024 001024 00000c 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 001024 000048 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 00106c 0000ee 00      0   0  1
  [28] .symtab           SYMTAB          00000000 00160c 000460 10     29  46  4
  [29] .strtab           STRTAB          00000000 001a6c 00025a 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
果然发现了问题,在14行红色标记行,.text段的起始地址赤裸裸的是0x080483a0,而不是上面输出结果显示的0x8048454(输出结果红色行)。

为什么呢?再把符号表截取出来:
Symbol table '.symtab' contains 70 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
    27: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 08049f0c     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_LIST__
    29: 08049f14     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_LIST__
    30: 08049f1c     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    31: 080483d0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
    32: 0804a024     1 OBJECT  LOCAL  DEFAULT   25 completed.7021
    33: 0804a028     4 OBJECT  LOCAL  DEFAULT   25 dtor_idx.7023
    34: 08048430     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
    35: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    36: 08049f10     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_END__
    37: 080486f0     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    38: 08049f1c     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    39: 080485e0     0 FUNC    LOCAL  DEFAULT   14 __do_global_ctors_aux
    40: 00000000     0 FILE    LOCAL  DEFAULT  ABS memlayout.c
    41: 0804a020     4 OBJECT  LOCAL  DEFAULT   24 localstaticval.2184
    42: 08049ff4     0 OBJECT  LOCAL  HIDDEN   23 _GLOBAL_OFFSET_TABLE_
    43: 08049f0c     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_end
    44: 08049f0c     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_start
    45: 08049f20     0 OBJECT  LOCAL  HIDDEN   21 _DYNAMIC
    46: 0804a014     0 NOTYPE  WEAK   DEFAULT   24 data_start
    47: 0804a02c     4 OBJECT  GLOBAL DEFAULT   25 global_noninit_val
    48: 08048570     5 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    49: 080483a0     0 FUNC    GLOBAL DEFAULT   14 _start
    50: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    51: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    52: 08048628     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    53: 0804860c     0 FUNC    GLOBAL DEFAULT   15 _fini
    54: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    55: 0804862c     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    56: 00000000     0 FUNC    GLOBAL DEFAULT  UND free@@GLIBC_2.0
    57: 0804a014     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    58: 0804a018     0 OBJECT  GLOBAL HIDDEN   24 __dso_handle
    59: 0804a01c     4 OBJECT  GLOBAL DEFAULT   24 global_init_val
    60: 08049f18     0 OBJECT  GLOBAL HIDDEN   19 __DTOR_END__
    61: 08048580    90 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    62: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.0
    63: 0804a024     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    64: 00000000     0 FUNC    GLOBAL DEFAULT  UND malloc@@GLIBC_2.0
    65: 0804a030     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    66: 0804a024     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    67: 080485da     0 FUNC    GLOBAL HIDDEN   14 __i686.get_pc_thunk.bx
    68: 08048454   269 FUNC    GLOBAL DEFAULT   14 main
    69: 08048304     0 FUNC    GLOBAL DEFAULT   12 _init
看68行(红色标记),发现0x080483a0地址对应的段是_start,08048454对应的是main段,所以验证程序的 printf("address of text  is:%p\n",main)并不能真正的打印出.text段
的起始地址,我认为事实上在编译成汇编代码的时候,main函数前面加入了一段代码,应该是编译器做的。
这个验证程序是一本书上看到的,当时看的时候就觉得不太准确,所以做了个实验来验证一下。当然这段程序估计还有其他地方不够严谨,下次看有没有机会再深入研究一下。
我发现当深入到编译器或系统层面理解代码之后以前的很多疑问顺其自然的解决了。
比如说请看41、47和59行全局变量和局部变量的属性区别就显现出来了,当然这是根据分页数据保护实现的。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章