1. 程式人生 > >7.6. 一個C程式的記憶體佈局(memory layout)

7.6. 一個C程式的記憶體佈局(memory layout)

7.6.一個C程式的記憶體佈局(memory layout)
一個C程式一直以來都是由以下5個段(pieces)組成:

程式碼段(text segment):存放CPU執行的機器指令(machine instructions)。通常情況下,程式碼段是可共享的,使其可共享的目的是對於頻繁被執行的程式,只需要在記憶體中有一份拷貝即可,比如文字編輯器(text editors),C編譯器,shell等等。另外,程式碼段也通常是隻讀的,使其只讀的原因是防止一個程式意外地修改了它的指令(prevent a program from accidentally modifying its instructions)。

初始化資料段/資料段(initialized data segment/data segment):該段包含了在程式中明確被初始化的變數。例如,一個不在任何函式內的C宣告(C declaration)
int   maxcount = 99;
使得變數maxcount根據其初始值被儲存到初始化資料段。

未初始化資料段/bss段(uninitialized data segment/"bss" segment):bss這個叫法是根據一個早期的彙編運算子而來,這個彙編運算子標誌著一個塊的開始(stood for "block started by symbol")。在程式開始執行之前,bss段的資料被kernel初始化為0或者空指標(null pointers)。一個不在任何函式內的C宣告
long  sum[1000];
使得變數sum被儲存到未初始化資料段/bss段中。

棧段(stack):where automatic variables are stored, along with information that is saved each time a function is called. 每次當一個函式被呼叫,該函式的返回地址和一些關於caller的資訊,比如某些暫存器的內容,將被首先儲存到棧段。然後這個被呼叫的函式(caller)再為它的自動變數和臨時變數(automatic and temporary variables)在棧段上分配空間。這就是C如何實現函式的遞迴呼叫。每次一個遞迴函式呼叫其本身,一個新的棧框架(stack frame)就會被使用,這樣這個新例項棧裡的一組變數就不會和該函式的另一個例項棧裡面的變數互相干擾。

堆段(heap):用於動態記憶體分配(dynamic memory allocation)。一直以來,堆在記憶體中的位置是介於bss段和棧段之間。

圖7.6顯示了這5個段在記憶體中的典型排列。這是一張邏輯圖,表示了一個程式在記憶體中看起來是怎麼樣的。對於一個給定的實現,沒有強制的要求說必須按照這種方式來排列這5個段。然而,這給了我們一種典型的便於描述的排列方式。執行在Intel x86處理器上的linux,程式碼段(text segment)從地址0x08048000開始(往上),棧底從地址0xC0000000往下(在這個特定的表示結構中,棧段從高地址向低地址擴充套件)。在堆頂和棧頂之間的虛擬地址空間是很大的(這保證了2個段不會互相干擾)。


在一個a.out中,還有許多段型別存在(Several more segment types exist in an a.out)。如符號表(symbol table),除錯資訊(debugging information),動態共享庫的連線表(linkage tables for dynamic shared libraries)等。這些額外的section(不是segment)不會作為被一個程序執行的程式映象的一部分。

從圖7.6中要注意到bss段的內容沒有被儲存到磁碟上的程式檔案中(the program file on disk)。這是因為kernel在程式開始執行之前將該段都置為0。程式中唯一需要被儲存到程式檔案中的部分是程式碼段和初始化資料段。

命令size會報告這3個段的大小:程式碼段,初始化資料段,未初始化資料段。例如:
$ size /usr/bin/cc /bin/sh
       text     data   bss     dec     hex   filename
      79606     1536   916   82058   1408a   /usr/bin/cc
     619234    21120 18260  658614   a0cb6   /bin/sh
第四和第五列是這3個段的總計大小,分別以十進位制和十六進位制表示出來。