久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

內(nèi)存區(qū)域分配與ELF 之類的關(guān)系

 Harper666 2018-02-05

轉(zhuǎn)載地址:http://blog.csdn.net/u012398613/article/details/52368408

一.

在學(xué)習(xí)之前我們先看看ELF文件。


ELF分為三種類型:.o 可重定位文件(relocalble file),,可執(zhí)行文件以及共享庫(kù)(shared library),,三種格式基本上從結(jié)構(gòu)上是一樣的,只是具體到每一個(gè)結(jié)構(gòu)不同,。下面我們就從整體上看看這3種格式從文件內(nèi)容上存儲(chǔ)的方式,,spec上有張圖是比較經(jīng)典的:如上圖:
 其實(shí)從文件存儲(chǔ)的格式來(lái)說(shuō),上面的兩種view實(shí)際上是一樣的,,Segment實(shí)際上就是由section組成的,,將相應(yīng)的一些section映射到一起就叫segment了,就是說(shuō)segment是由0個(gè)或多個(gè)section組成的,,實(shí)際上本質(zhì)都是section,。在這里我們首先來(lái)仔細(xì)了解一下section和segment的概念:section就是相同或者相似信息的集合,,比如我們比較熟悉的.text .data  .bss section,.text是可執(zhí)行指令的集合,,.data是初始化后數(shù)據(jù)的集合,,.bss是未初始化數(shù)據(jù)的集合。實(shí)際上我們也可以將一個(gè)程序的所有內(nèi)容都放在一起,,就像dos一樣,,但是將可執(zhí)行程序分成多個(gè)section是很有好處的,比如說(shuō)我們可以將.text section放在memory的只讀空間內(nèi),,將可變的.data section放在memory的可寫空間內(nèi)。

從可執(zhí)行文件的角度來(lái)講,,如果一個(gè)數(shù)據(jù)未被初始化那就不需要為其分配空間,,所以.data和.bss一個(gè)重要的區(qū)別就是.bss并不占用可執(zhí)行文件的大小,它只是記載需要多少空間來(lái)存儲(chǔ)這些未初始化數(shù)據(jù),,而不分配實(shí)際的空間,。

可以通過(guò)命令 $ readelf -l a.out 查看文件的格式和組成。

二.

站在匯編語(yǔ)言的角度,,一個(gè)程序分為:
數(shù)據(jù)段 -- DS
堆棧段 -- SS
代碼段 -- CS
擴(kuò)展段 -- ES

站在高級(jí)語(yǔ)言的角度,,根據(jù)APUE,一個(gè)程序分為如下段:
text
data (initialized)
bss
stack
heap

        1.一般情況下,,一個(gè)可執(zhí)行二進(jìn)制程序(更確切的說(shuō),,在Linux操作系統(tǒng)下為一個(gè)進(jìn)程單元,在UC/OSII中被稱為任務(wù))在存儲(chǔ)(沒(méi)有調(diào)入到內(nèi)存運(yùn)行)時(shí)擁有3個(gè)部分,,分別是代碼段(text),、數(shù)據(jù)段(data)和BSS段,。這3個(gè)部分一起組成了該可執(zhí)行程序的文件

可執(zhí)行二進(jìn)制程序 = 代碼段(text)+數(shù)據(jù)段(data)+BSS段

        2.而當(dāng)程序被加載到內(nèi)存單元時(shí),,則需要另外兩個(gè)域:堆域和棧域,。圖1-1所示為可執(zhí)行代碼存儲(chǔ)態(tài)運(yùn)行態(tài)的結(jié)構(gòu)對(duì)照?qǐng)D。一個(gè)正在運(yùn)行的C程序占用的內(nèi)存區(qū)域分為代碼段,、初始化數(shù)據(jù)段,、未初始化數(shù)據(jù)段(BSS)、堆,、棧5個(gè)部分,。

正在運(yùn)行的C程序 = 代碼段+初始化數(shù)據(jù)段(data)+未初始化數(shù)據(jù)段(BSS)+堆+棧

       3.在將應(yīng)用程序加載到內(nèi)存空間執(zhí)行時(shí),操作系統(tǒng)負(fù)責(zé)代碼段,、數(shù)據(jù)段和BSS段的加載,,并將在內(nèi)存中為這些段分配空間。棧亦由操作系統(tǒng)分配和管理,,而不需要程序員顯示地管理,;堆段由程序員自己管理,即顯示地申請(qǐng)和釋放空間,。

          4.動(dòng)態(tài)分配與靜態(tài)分配,,二者最大的區(qū)別在于:1. 直到Run-Time的時(shí)候,執(zhí)行動(dòng)態(tài)分配,,而在compile-time的時(shí)候,,就已經(jīng)決定好了分配多少Text+Data+BSS+Stack2.通過(guò)malloc()動(dòng)態(tài)分配的內(nèi)存,,需要程序員手工調(diào)用free()釋放內(nèi)存,,否則容易導(dǎo)致內(nèi)存泄露,而靜態(tài)分配的內(nèi)存則在進(jìn)程執(zhí)行結(jié)束后系統(tǒng)釋放(Text, Data), Stack段中的數(shù)據(jù)很短暫,,函數(shù)退出立即被銷毀,。



 圖1-1從可執(zhí)行文件a.out的角度來(lái)講,如果一個(gè)數(shù)據(jù)未被初始化那就不需要為其分配空間,,所以.data和.bss一個(gè)重要的區(qū)別就是.bss并不占用可執(zhí)行文件的大小,,它只是記載需要多少空間來(lái)存儲(chǔ)這些未初始化數(shù)據(jù),而不分配實(shí)際的空間

三.

代碼段 --textcode segment/text segment)
text段在內(nèi)存中被映射為只讀,,但.data和.bss是可寫的,。
text段是程序代碼段,在AT91庫(kù)中是表示程序段的大小,,它是由編譯器在編譯連接時(shí)自動(dòng)計(jì)算的,,當(dāng)你在鏈接定位文件中將該符號(hào)放置在代碼段后,那么該符號(hào)表示的值就是代碼段大小,,編譯連接時(shí),,該符號(hào)所代表的值會(huì)自動(dòng)代入到源程序中,。

數(shù)據(jù)段 -- data
data包含靜態(tài)初始化的數(shù)據(jù),所以有初值的全局變量和static變量在data區(qū),。段的起始位置也是由連接定位文件所確定,,大小在編譯連接時(shí)自動(dòng)分配,它和你的程序大小沒(méi)有關(guān)系,,但和程序使用到的全局變量,,常量數(shù)量相關(guān)。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配,。 

bss段--bss
bss是英文Block Started by Symbol的簡(jiǎn)稱,,通常是指用來(lái)存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域,在程序載入時(shí)由內(nèi)核清0,。BSS段屬于靜態(tài)內(nèi)存分配,。它的初始值也是由用戶自己定義的連接定位文件所確定,用戶應(yīng)該將它定義在可讀寫的RAM區(qū)內(nèi),,源程序中使用malloc分配的內(nèi)存就是這一塊,,它不是根據(jù)data大小確定,主要由程序中同時(shí)分配內(nèi)存最大值所確定,,不過(guò)如果超出了范圍,,也就是分配失敗,可以等空間釋放之后再分配,。BSS段屬于靜態(tài)內(nèi)存分配,。

stack:
棧(stack)保存函數(shù)的局部變量(但不包括static聲明的變量, static 意味著 在數(shù)據(jù)段中 存放變量),,參數(shù)以及返回值,。是一種“后進(jìn)先出”(Last In First Out,LIFO)的數(shù)據(jù)結(jié)構(gòu),,這意味著最后放到棧上的數(shù)據(jù),,將會(huì)是第一個(gè)從棧上移走的數(shù)據(jù)。對(duì)于哪些暫時(shí)存貯的信息,,和不需要長(zhǎng)時(shí)間保存的信息來(lái)說(shuō),,LIFO這種數(shù)據(jù)結(jié)構(gòu)非常理想,。在調(diào)用函數(shù)或過(guò)程后,,系統(tǒng)通常會(huì)清除棧上保存的局部變量、函數(shù)調(diào)用信息及其它的信息,。棧另外一個(gè)重要的特征是,,它的地址空間“向下減少”,即當(dāng)棧上保存的數(shù)據(jù)越多,,棧的地址就越低,。棧(stack)的頂部在可讀寫的RAM區(qū)的最后,。

heap:
堆(heap)保存函數(shù)內(nèi)部動(dòng)態(tài)分配內(nèi)存,是另外一種用來(lái)保存程序信息的數(shù)據(jù)結(jié)構(gòu),,更準(zhǔn)確的說(shuō)是保存程序的動(dòng)態(tài)變量,。堆是“先進(jìn)先出”(First In first Out,F(xiàn)IFO)數(shù)據(jù)結(jié)構(gòu),。它只允許在堆的一端插入數(shù)據(jù),,在另一端移走數(shù)據(jù)。堆的地址空間“向上增加”,,即當(dāng)堆上保存的數(shù)據(jù)越多,,堆的地址就越高。

下圖是APUE中的一個(gè)典型C內(nèi)存空間分布圖:


所以可以知道傳入的參數(shù),局部變量,都是在棧頂分布,隨著子函數(shù)的增多而向下增長(zhǎng).
函數(shù)的調(diào)用地址(函數(shù)運(yùn)行代碼),全局變量,靜態(tài)變量都是在分配內(nèi)存的低部存在,而malloc分配的堆則存在于這些內(nèi)存之上,并向上生長(zhǎng).

舉例1:

  1. #include <stdio h="">  
  2. const int    g_A       = 10;         //代碼段  
  3. int          g_B       = 20;         //數(shù)據(jù)段  
  4. static int   g_C       = 30;         //數(shù)據(jù)段  
  5. static int   g_D;                    //BSS段  
  6. int          g_E;                    //BSS段  
  7. char        *p1;                     //BSS段  
  8.   
  9. void main( )  
  10. {  
  11.     int           local_A;            //棧  
  12.     int           local_B;            //棧  
  13.     static int    local_C = 0;        //數(shù)據(jù)段  
  14.     static int    local_D;            //數(shù)據(jù)段  
  15.       
  16.     char        *p3 = "123456";     //123456在代碼段,,p3在棧上  
  17.   
  18.     p1 = (char *)malloc( 10 );      //堆,,分配得來(lái)得10字節(jié)的區(qū)域在堆區(qū)  
  19.     strcpy( p1, "123456" );         //123456{post.content}放在常量區(qū),編譯器可能會(huì)將它與p3所指向 的"123456"優(yōu)化成一塊  
  20.   
  21.     printf("hight address\n");  
  22.     printf("-------------棧--------------\n");  
  23.     printf( "棧,    局部變量,                           local_A, addr:0x%08x\n", &local_A );  
  24.     printf( "棧,    局部變量,(后進(jìn)棧地址相對(duì)local_A低)  local_B, addr:0x%08x\n", &local_B );  
  25.     printf("-------------堆--------------\n");  
  26.     printf( "堆,    malloc分配內(nèi)存,             p1,      addr:0x%08x\n", p1 );  
  27.     printf("------------BSS段------------\n");  
  28.     printf( "BSS段, 全局變量,       未初始化    g_E,     addr:0x%08x\n", &g_E, g_E );      
  29.     printf( "BSS段, 靜態(tài)全局變量,   未初始化,   g_D,     addr:0x%08x\n", &g_D );  
  30.     printf( "BSS段, 靜態(tài)局部變量,   初始化,     local_C, addr:0x%08x\n", &local_C);  
  31.     printf( "BSS段, 靜態(tài)局部變量,   未初始化,   local_D, addr:0x%08x\n", &local_D);  
  32.     printf("-----------數(shù)據(jù)段------------\n");  
  33.     printf( "數(shù)據(jù)段,全局變量,       初始化      g_B,     addr:0x%08x\n", &g_B);  
  34.     printf( "數(shù)據(jù)段,靜態(tài)全局變量,   初始化,     g_C,     addr:0x%08x\n", &g_C);  
  35.     printf("-----------代碼段------------\n");  
  36.     printf( "代碼段,全局初始化變量, 只讀const,  g_A,     addr:0x%08x\n\n", &g_A);  
  37.     printf("low address\n");  
  38.     return;  
  39. }  
  40. </stdio>  

運(yùn)行結(jié)果:

  1. hight address  
  2. -------------棧--------------  
  3. 棧,    局部變量,                           local_A, addr:0xffa70c1c  
  4. 棧,    局部變量,(后進(jìn)棧地址相對(duì)local_A低)  local_B, addr:0xffa70c18  
  5. -------------堆--------------  
  6. 堆,    malloc分配內(nèi)存,             p1,      addr:0x087fe008  
  7. ------------BSS段------------  
  8. BSS段, 全局變量,       未初始化    g_E,     addr:0x08049a64  
  9. BSS段, 靜態(tài)全局變量,   未初始化,   g_D,     addr:0x08049a5c  
  10. BSS段, 靜態(tài)局部變量,   初始化,     local_C, addr:0x08049a58  
  11. BSS段, 靜態(tài)局部變量,   未初始化,   local_D, addr:0x08049a54  
  12. -----------數(shù)據(jù)段------------  
  13. 數(shù)據(jù)段,全局變量,       初始化      g_B,     addr:0x08049a44  
  14. 數(shù)據(jù)段,靜態(tài)全局變量,   初始化,     g_C,     addr:0x08049a48  
  15. -----------代碼段------------  
  16. 代碼段,全局初始化變量, 只讀const,  g_A,     addr:0x08048620  
  17.   
  18. low address  

注意:
編譯時(shí)需要-g選項(xiàng),,這樣才可以看elf信息,;
readelf -a a.out 

查看這個(gè)執(zhí)行文件的elf信息,摘錄部分如下:重點(diǎn)注意其中data段,,text段還要有bss段的地址,,然后比較這個(gè)地址和上面的運(yùn)行結(jié)果,是否是在elf文件的各個(gè)段的地址之內(nèi),。

  1. Section Headers:  
  2.   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al  
  3.   [ 0]                   NULL            00000000 000000 000000 00      0   0  0  
  4.   [ 1] .interp           PROGBITS        08048114 000114 000013 00   A  0   0  1  
  5.   [ 2] .note.ABI-tag     NOTE            08048128 000128 000020 00   A  0   0  4  
  6.   [ 3] .gnu.hash         GNU_HASH        08048148 000148 000020 04   A  4   0  4  
  7.   [ 4] .dynsym           DYNSYM          08048168 000168 000070 10   A  5   1  4  
  8.   [ 5] .dynstr           STRTAB          080481d8 0001d8 000058 00   A  0   0  1  
  9.   [ 6] .gnu.version      VERSYM          08048230 000230 00000e 02   A  4   0  2  
  10.   [ 7] .gnu.version_r    VERNEED         08048240 000240 000020 00   A  5   1  4  
  11.   [ 8] .rel.dyn          REL             08048260 000260 000008 08   A  4   0  4  
  12.   [ 9] .rel.plt          REL             08048268 000268 000028 08   A  4  11  4  
  13.   [10] .init             PROGBITS        08048290 000290 000017 00  AX  0   0  4  
  14.   [11] .plt              PROGBITS        080482a8 0002a8 000060 04  AX  0   0  4  
  15.   [12] .text             PROGBITS        08048310 000310 0002e8 00  AX  0   0 16  
  16.   [13] .fini             PROGBITS        080485f8 0005f8 00001c 00  AX  0   0  4  
  17.   [14] .rodata           PROGBITS        08048614 000614 000326 00   A  0   0  4  
  18.   [15] .eh_frame         PROGBITS        0804893c 00093c 000004 00   A  0   0  4  
  19.   [16] .ctors            PROGBITS        08049940 000940 000008 00  WA  0   0  4  
  20.   [17] .dtors            PROGBITS        08049948 000948 000008 00  WA  0   0  4  
  21.   [18] .jcr              PROGBITS        08049950 000950 000004 00  WA  0   0  4  
  22.   [19] .dynamic          DYNAMIC         08049954 000954 0000c8 08  WA  5   0  4  
  23.   [20] .got              PROGBITS        08049a1c 000a1c 000004 04  WA  0   0  4  
  24.   [21] .got.plt          PROGBITS        08049a20 000a20 000020 04  WA  0   0  4  
  25.   [22] .data             PROGBITS        08049a40 000a40 00000c 00  WA  0   0  4  
  26.   [23] .bss              NOBITS          08049a4c 000a4c 00001c 00  WA  0   0  4  
  27.   [24] .comment          PROGBITS        00000000 000a4c 000114 00      0   0  1  
  28.   [25] .debug_aranges    PROGBITS        00000000 000b60 000020 00      0   0  1  
  29.   [26] .debug_pubnames   PROGBITS        00000000 000b80 00003a 00      0   0  1  
  30.   [27] .debug_info       PROGBITS        00000000 000bba 0001f4 00      0   0  1  
  31.   [28] .debug_abbrev     PROGBITS        00000000 000dae 00006f 00      0   0  1  
  32.   [29] .debug_line       PROGBITS        00000000 000e1d 000058 00      0   0  1  
  33.   [30] .debug_frame      PROGBITS        00000000 000e78 00003c 00      0   0  4  
  34.   [31] .debug_str        PROGBITS        00000000 000eb4 00000d 00      0   0  1  
  35.   [32] .debug_loc        PROGBITS        00000000 000ec1 000043 00      0   0  1  
  36.   [33] .shstrtab         STRTAB          00000000 000f04 000143 00      0   0  1  
  37.   [34] .symtab           SYMTAB          00000000 0015e8 000560 10     35  60  4  
  38.   [35] .strtab           STRTAB          00000000 001b48 0002ad 00      0   0  1  
  39. Key to Flags:  
  40.   W (write), A (alloc), X (execute), M (merge), S (strings)  
  41.   I (info), L (link order), G (group), x (unknown)  
  42.   O (extra OS processing required) o (OS specific), p (processor specific)  

注意靜態(tài)變量初始化為零全局靜態(tài)變量初始化為零的情況,,都是存儲(chǔ)在bss段★★★

從上面的elf文件可以看出,

  [23] .bss              NOBITS          08049a4c 000a4c 00001c 00  WA  0   0  4

  [22] .data             PROGBITS    08049a40000a40 00000c 00  WA  0   0  4

  [12] .text             PROGBITS      08048310000310 0002e8 00  AX  0   0 16

但是在結(jié)果中顯示: BSS段, 靜態(tài)局部變量,   初始化,    local_C, addr:0x08049a58 

 (0x08049a58 大于0x08049a4c 屬于bss段)是初始化的靜態(tài)局部變量但是卻屬于bss段,,為什么,?

原因是:local_C是局部靜態(tài)變量但是卻初始化為零。這和沒(méi)有初始化,,默認(rèn)是零的情況一樣,,都存儲(chǔ)在bss段,如果初始化為其他的值,,那么local_C這個(gè)變量就會(huì)存儲(chǔ)在data段,。

可執(zhí)行文件大小由什么決定?

可執(zhí)行文件在存儲(chǔ)時(shí)分為代碼段,、數(shù)據(jù)段和BSS段三個(gè)部分,。

【例一】
程序1:
int ar[30000];
void main()
{
    ......

程序2:
int ar[300000] =  {1, 2, 3, 4, 5, 6 };
void main()
{
    ......

發(fā)現(xiàn)程序2編譯之后所得的.exe文件比程序1的要大得多。當(dāng)下甚為不解,,于是手工編譯了一下,,并使用了/FAs編譯選項(xiàng)來(lái)查看了一下其各自的.asm,發(fā)現(xiàn)在程序1.asm中ar的定義如下:
_BSS SEGMENT
     ?ar@@3PAHA DD 0493e0H DUP (?)    ; ar
_BSS ENDS 
而在程序2.asm中,ar被定義為:
_DATA SEGMENT
     ?ar@@3PAHA DD 01H     ; ar
                DD 02H
                DD 03H
                ORG $+1199988
_DATA ENDS 
區(qū)別很明顯,,一個(gè)位于.bss段,,而另一個(gè)位于.data段,兩者的區(qū)別在于:全局的未初始化變量存在于.bss段中,,具體體現(xiàn)為一個(gè)占位符,;全局的已初始化變量存于.data段中;而函數(shù)內(nèi)的自動(dòng)變量都在棧上分配空間,。

.bss是不占用.exe文件空間的,,其內(nèi)容由操作系統(tǒng)初始化(清零);而.data卻需要占用,,其內(nèi)容由程序初始化,,因此造成了上述情況。


以上僅僅做為學(xué)習(xí)只用??!

參考材料:
C程序內(nèi)存區(qū)域分配(5個(gè)段作用)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多