一個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行全局變量和局部變量的屬性區別就顯現出來了,當然這是根據分頁數據保護實現的。



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