亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

程序或-內存區域分配(五個段)

2019-11-10 17:58:04
字體:
來源:轉載
供稿:網友

一.

在學習之前我們先看看ELF文件。

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

從可執行文件的角度來講,如果一個數據未被初始化那就不需要為其分配空間,所以.data和.bss一個重要的區別就是.bss并不占用可執行文件的大小,它只是記載需要多少空間來存儲這些未初始化數據,而不分配實際的空間。

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

二.

站在匯編語言的角度,一個程序分為:數據段 -- DS堆棧段 -- SS代碼段 -- CS擴展段 -- ES

站在高級語言的角度,根據APUE,一個程序分為如下段:textdata (initialized)bssstackheap

        1.一般情況下,一個可執行二進制程序(更確切的說,在linux操作系統下為一個進程單元,在UC/OSII中被稱為任務)在存儲(沒有調入到內存運行)時擁有3個部分,分別是代碼段(text)、數據段(data)和BSS段。這3個部分一起組成了該可執行程序的文件。

可執行二進制程序 = 代碼段(text)+數據段(data)+BSS段

        2.而當程序被加載到內存單元時,則需要另外兩個域:堆域和棧域。圖1-1所示為可執行代碼存儲態和運行態的結構對照圖。一個正在運行的C程序占用的內存區域分為代碼段、初始化數據段、未初始化數據段(BSS)、堆、棧5個部分。

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

       3.在將應用程序加載到內存空間執行時,操作系統負責代碼段、數據段和BSS段的加載,并將在內存中為這些段分配空間。棧亦由操作系統分配和管理,而不需要程序員顯示地管理;堆段由程序員自己管理,即顯示地申請和釋放空間。

          4.動態分配與靜態分配,二者最大的區別在于:1. 直到Run-Time的時候,執行動態分配,而在compile-time的時候,就已經決定好了分配多少Text+Data+BSS+Stack。2.通過malloc()動態分配的內存,需要程序員手工調用free()釋放內存,否則容易導致內存泄露,而靜態分配的內存則在進程執行結束后系統釋放(Text, Data), 但Stack段中的數據很短暫,函數退出立即被銷毀。

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

三.

代碼段 --text(code segment/text segment)text段在內存中被映射為只讀,但.data和.bss是可寫的。text段是程序代碼段,在AT91庫中是表示程序段的大小,它是由編譯器在編譯連接時自動計算的,當你在鏈接定位文件中將該符號放置在代碼段后,那么該符號表示的值就是代碼段大小,編譯連接時,該符號所代表的值會自動代入到源程序中。

數據段 -- datadata包含靜態初始化的數據,所以有初值的全局變量和static變量在data區。段的起始位置也是由連接定位文件所確定,大小在編譯連接時自動分配,它和你的程序大小沒有關系,但和程序使用到的全局變量,常量數量相關。數據段屬于靜態內存分配。 

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

stack:棧(stack)保存函數的局部變量(但不包括static聲明的變量, static 意味著 在數據段中 存放變量),參數以及返回值。是一種“后進先出”(Last In First Out,LIFO)的數據結構,這意味著最后放到棧上的數據,將會是第一個從棧上移走的數據。對于哪些暫時存貯的信息,和不需要長時間保存的信息來說,LIFO這種數據結構非常理想。在調用函數或過程后,系統通常會清除棧上保存的局部變量、函數調用信息及其它的信息。棧另外一個重要的特征是,它的地址空間“向下減少”,即當棧上保存的數據越多,棧的地址就越低。棧(stack)的頂部在可讀寫的RAM區的最后。

heap:堆(heap)保存函數內部動態分配內存,是另外一種用來保存程序信息的數據結構,更準確的說是保存程序的動態變量。堆是“先進先出”(First In first Out,FIFO)數據結構。它只允許在堆的一端插入數據,在另一端移走數據。堆的地址空間“向上增加”,即當堆上保存的數據越多,堆的地址就越高。

下圖是APUE中的一個典型C內存空間分布圖:

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

舉例1:

[c] view plain copy#include <stdio h="">  const int    g_A       = 10;         //代碼段  int          g_B       = 20;         //數據段  static int   g_C       = 30;         //數據段  static int   g_D;                    //BSS段  int          g_E;                    //BSS段  char        *p1;                     //BSS段    void main( )  {      int           local_A;            //棧      int           local_B;            //棧      static int    local_C = 0;        //數據段      static int    local_D;            //數據段            char        *p3 = "123456";     //123456在代碼段,p3在棧上        p1 = (char *)malloc( 10 );      //堆,分配得來得10字節的區域在堆區      strcpy( p1, "123456" );         //123456{post.content}放在常量區,編譯器可能會將它與p3所指向 的"123456"優化成一塊        PRintf("hight address/n");      printf("-------------棧--------------/n");      printf( "棧,    局部變量,                           local_A, addr:0x%08x/n", &local_A );      printf( "棧,    局部變量,(后進棧地址相對local_A低)  local_B, addr:0x%08x/n", &local_B );      printf("-------------堆--------------/n");      printf( "堆,    malloc分配內存,             p1,      addr:0x%08x/n", p1 );      printf("------------BSS段------------/n");      printf( "BSS段, 全局變量,       未初始化    g_E,     addr:0x%08x/n", &g_E, g_E );          printf( "BSS段, 靜態全局變量,   未初始化,   g_D,     addr:0x%08x/n", &g_D );      printf( "BSS段, 靜態局部變量,   初始化,     local_C, addr:0x%08x/n", &local_C);      printf( "BSS段, 靜態局部變量,   未初始化,   local_D, addr:0x%08x/n", &local_D);      printf("-----------數據段------------/n");      printf( "數據段,全局變量,       初始化      g_B,     addr:0x%08x/n", &g_B);      printf( "數據段,靜態全局變量,   初始化,     g_C,     addr:0x%08x/n", &g_C);      printf("-----------代碼段------------/n");      printf( "代碼段,全局初始化變量, 只讀const,  g_A,     addr:0x%08x/n/n", &g_A);      printf("low address/n");      return;  }  </stdio>  

運行結果:

[c] view plain copyhight address  -------------棧--------------  棧,    局部變量,                           local_A, addr:0xffa70c1c  棧,    局部變量,(后進棧地址相對local_A低)  local_B, addr:0xffa70c18  -------------堆--------------  堆,    malloc分配內存,             p1,      addr:0x087fe008  ------------BSS段------------  BSS段, 全局變量,       未初始化    g_E,     addr:0x08049a64  BSS段, 靜態全局變量,   未初始化,   g_D,     addr:0x08049a5c  BSS段, 靜態局部變量,   初始化,     local_C, addr:0x08049a58  BSS段, 靜態局部變量,   未初始化,   local_D, addr:0x08049a54  -----------數據段------------  數據段,全局變量,       初始化      g_B,     addr:0x08049a44  數據段,靜態全局變量,   初始化,     g_C,     addr:0x08049a48  -----------代碼段------------  代碼段,全局初始化變量, 只讀const,  g_A,     addr:0x08048620    low address  

注意:編譯時需要-g選項,這樣才可以看elf信息;readelf -a a.out 

查看這個執行文件的elf信息,摘錄部分如下:重點注意其中data段,text段還要有bss段的地址,然后比較這個地址和上面的運行結果,是否是在elf文件的各個段的地址之內。

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

注意靜態變量初始化為零和全局靜態變量初始化為零的情況,都是存儲在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

但是在結果中顯示: BSS段, 靜態局部變量,   初始化,    local_C, addr:0x08049a58 

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

原因是:local_C是局部靜態變量但是卻初始化為零。這和沒有初始化,默認是零的情況一樣,都存儲在bss段,如果初始化為其他的值,那么local_C這個變量就會存儲在data段。

可執行文件大小由什么決定?

可執行文件在存儲時分為代碼段、數據段和BSS段三個部分。

【例一】程序1:int ar[30000];void main(){    ......} 程序2:int ar[300000] =  {1, 2, 3, 4, 5, 6 };void main(){    ......} 發現程序2編譯之后所得的.exe文件比程序1的要大得多。當下甚為不解,于是手工編譯了一下,并使用了/FAs編譯選項來查看了一下其各自的.asm,發現在程序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 區別很明顯,一個位于.bss段,而另一個位于.data段,兩者的區別在于:全局的未初始化變量存在于.bss段中,具體體現為一個占位符;全局的已初始化變量存于.data段中;而函數內的自動變量都在棧上分配空間。

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

以上僅僅做為學習只用!!

參考材料:可執行文件(ELF)格式的理解http://www.cnblogs.com/xmphoenix/archive/2011/10/23/2221879.htmlC程序內存區域分配(5個段作用)http://www.cnblogs.com/bigbigtree/archive/2012/11/23/2784137.html
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
青青久久av北条麻妃海外网| 国产人妖伪娘一区91| 久久99久久99精品免观看粉嫩| 亚洲电影中文字幕| 久久影视电视剧免费网站清宫辞电视| 性欧美xxxx| 成人免费自拍视频| 亚洲娇小xxxx欧美娇小| 亚洲欧美国产精品va在线观看| 日韩精品视频中文在线观看| 日韩电影免费在线观看中文字幕| 欧美黄色小视频| 国产精品草莓在线免费观看| 精品久久久香蕉免费精品视频| 清纯唯美日韩制服另类| 国外日韩电影在线观看| 青青久久av北条麻妃黑人| 国产精品女人久久久久久| 45www国产精品网站| 国产91精品黑色丝袜高跟鞋| 中文字幕亚洲一区二区三区五十路| 日韩av在线电影网| 97久久精品人人澡人人爽缅北| 国产精品毛片a∨一区二区三区|国| 欧美日韩亚洲一区二区三区| 美日韩精品视频免费看| 亚洲最新中文字幕| 日韩女在线观看| 欧美国产日韩xxxxx| 蜜月aⅴ免费一区二区三区| 福利一区福利二区微拍刺激| 在线观看日韩www视频免费| 国产精品在线看| 国内免费精品永久在线视频| 久久亚洲精品国产亚洲老地址| 欧美日韩在线视频观看| 欧美在线国产精品| 日韩av免费在线| 日本午夜精品理论片a级appf发布| 中文字幕av一区| 国产日本欧美一区二区三区| 亚洲成人精品在线| 亚洲一区二区三区sesese| 欧美午夜电影在线| 国产精品在线看| 这里只有精品视频| 国产成人精品999| 欧美黄色成人网| 欧美专区中文字幕| 色悠悠久久88| 久热99视频在线观看| 日韩免费电影在线观看| 国产精品视频免费观看www| 日韩精品久久久久| 亚洲成人黄色在线| 成人福利在线观看| 亚洲欧洲国产精品| 庆余年2免费日韩剧观看大牛| 久久综合网hezyo| 欧美成人精品影院| 欧美黄色片在线观看| 亚洲天堂色网站| 色偷偷综合社区| 精品国内自产拍在线观看| 9.1国产丝袜在线观看| 国产日韩一区在线| 国产亚洲精品一区二区| 久热爱精品视频线路一| 久久久久五月天| 国产精品国产自产拍高清av水多| 国产亚洲欧洲高清一区| 97精品在线视频| 国产精品pans私拍| 欧美孕妇与黑人孕交| 国产精品久久久久久久久久99| 日韩精品在线观看网站| 自拍偷拍亚洲在线| 欧美在线视频免费观看| 久久综合久中文字幕青草| 欧美日韩国产黄| 91在线精品播放| 欧美激情欧美狂野欧美精品| 亚洲国产精品电影在线观看| 色噜噜亚洲精品中文字幕| 黑人巨大精品欧美一区二区免费| 777777777亚洲妇女| 国产成+人+综合+亚洲欧美丁香花| 一本色道久久88综合日韩精品| 国产精品揄拍一区二区| 青青久久av北条麻妃黑人| 欧美在线一区二区视频| 欧美精品日韩三级| 欧美激情亚洲国产| 久久久av网站| 欧美日韩一区二区在线| 欧美日韩成人在线视频| 一区二区成人精品| 欧美壮男野外gaytube| 欧美精品在线极品| 久久色精品视频| 国产精品青草久久久久福利99| 欧美成人免费视频| 777国产偷窥盗摄精品视频| 97人洗澡人人免费公开视频碰碰碰| 色悠久久久久综合先锋影音下载| 国产成人久久久| 91久久久久久久一区二区| 精品国产鲁一鲁一区二区张丽| 亚洲美女视频网| 欧美午夜影院在线视频| 欧美最近摘花xxxx摘花| 亚洲免费影视第一页| 一本一本久久a久久精品牛牛影视| 高清一区二区三区日本久| 国产精品自产拍在线观看| 欧美激情在线观看视频| 91免费的视频在线播放| 色综合久久中文字幕综合网小说| 欧美又大又硬又粗bbbbb| 国产自产女人91一区在线观看| 亚洲第一精品久久忘忧草社区| 欧美性猛交xxxx黑人猛交| 欧美国产高跟鞋裸体秀xxxhd| 国产综合香蕉五月婷在线| 97福利一区二区| 亚洲深夜福利在线| 丝袜一区二区三区| 欧美精品久久久久久久久久| 亚洲国产精品成人精品| 国产精品美女主播| 欧美激情视频一区二区三区不卡| 亚洲va男人天堂| 亚洲精品日韩激情在线电影| 亚洲第一网站男人都懂| 日韩经典中文字幕在线观看| 亚洲欧美精品在线| 精品国产乱码久久久久久婷婷| 国产日韩换脸av一区在线观看| 国产精品久久久久久av福利软件| 日本精品中文字幕| 欧美成人中文字幕在线| 国产精品无码专区在线观看| 亚洲综合中文字幕在线观看| 最近更新的2019中文字幕| 91sa在线看| www欧美xxxx| 成人欧美在线观看| 国产精品ⅴa在线观看h| 欧美亚洲午夜视频在线观看| 久久精品福利视频| 日韩视频免费观看| 91影院在线免费观看视频| 日韩久久免费视频| 欧美插天视频在线播放| 国产欧美精品一区二区三区-老狼| 精品久久久久久久久国产字幕| 红桃视频成人在线观看| 亚洲天堂免费在线| 亚洲影院色无极综合| 精品成人国产在线观看男人呻吟| 日本中文字幕成人| 国产精品久久久久9999| 国产精品免费一区二区三区都可以| **欧美日韩vr在线|