1. 程式人生 > >arm BSS段、資料段、程式碼段、堆與棧(也加上了我自己的見解)

arm BSS段、資料段、程式碼段、堆與棧(也加上了我自己的見解)

BSS段:BSS段(bss segment)通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體分配。

資料段:資料段(data segment)通常是指用來存放程式中已初始化的全域性變數的一塊記憶體區域。資料段屬於靜態記憶體分配。

程式碼段:程式碼段(code segment/text segment)通常是指用來存放程式執行程式碼的一塊記憶體區域。這部分割槽域的大小在程式執行前就已經確定,並且記憶體區域通常屬於只讀, 某些架構也允許程式碼段為可寫,即允許修改程式。在程式碼段中,也有可能包含一些只讀的常數變數,例如字串常量等。

堆(heap):堆是用於存放程序執行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。當程序呼叫malloc等函式分配記憶體時,新分配的記憶體就被動態新增到堆上(堆被擴張);當利用free等函式釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減)

棧(stack):棧又稱堆疊, 是使用者存放程式臨時建立的區域性變數,也就是說我們函式括弧“{}”中定義的變數(但不包括static宣告的變數,static意味著在資料段中存放變數)。除此以外,在函式被呼叫時,其引數也會被壓入發起呼叫的程序棧中,並且待到呼叫結束後,函式的返回值也會被存放回棧中。由於棧的先進先出特點,所以棧特別方便用來儲存/恢復呼叫現場。從這個意義上講,我們可以把堆疊看成一個寄存、交換臨時資料的記憶體區。         (如下圖彙編程式,其實區域性變數的本質就是通過對push和pop的操作出來的,而static變數和全域性變數就相當於將變數儲存在靜態記憶體處,是時時刻刻存在的,而不像區域性變數,只是在進入函式時,如下圖,賦值給al或cl,就成了可以操作的變數,一旦出了函式,就不復存在)  

【例一】

用cl編譯兩個小程式如下:
程式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
     [email protected]@3PAHA DD 0493e0H DUP (?)    ; ar
_BSS ENDS


而在程式2.asm中,ar被定義為:

_DATA SEGMENT
     [email protected]@3PAHA DD 01H     ; ar
                DD 02H
                DD 03H
                ORG $+1199988
_DATA ENDS
區別很明顯,一個位於.bss段,而另一個位於.data段,兩者的區別在於:全域性的未初始化變數存在於.bss段中,具體體現為一個佔位符;全域性的已初始化變數存於.data段中;而函式內的自動變數都在棧上分配空間。.bss是不佔用.exe檔案空間的,其內容由作業系統初始化(清零);而.data卻需要佔用,其內容由程式初始化,因此造成了上述情況。

【例二】

編譯如下程式(test.cpp:
#include <stdio.h>

#define LEN 1002000

int inbss[LEN];
float fA;
int indata[LEN]={1,2,3,4,5,6,7,8,9};
double dbB = 100.0;

const int cst = 100;

int main(void)
{
    int run[100] = {1,2,3,4,5,6,7,8,9};
    for(int i=0; i<LEN; ++i)
        printf("%d ", inbss[i]);
    return 0;
}
命令:cl /FA  test.cpp 回車 (/FA:產生彙編程式碼)
產生的彙編程式碼(test.asm):
    TITLE    test.cpp
    .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
_DATA    SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA    ENDS
CONST    SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST    ENDS
_BSS    SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS    ENDS
_TLS    SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS    ENDS
FLAT    GROUP _DATA, CONST, _BSS
    ASSUME    CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC    [email protected]@3PAHA                    ; inbss
PUBLIC    [email protected]@3MA                    ; fA
PUBLIC    [email protected]@3PAHA                    ; indata
PUBLIC    [email protected]@3NA                    ; dbB
_BSS    SEGMENT
[email protected]@3PAHA DD 0f4a10H DUP (?)            ; inbss
[email protected]@3MA DD    01H DUP (?)                ; fA
_BSS    ENDS
_DATA    SEGMENT
[email protected]@3PAHA DD 01H                    ; indata
    DD    02H
    DD    03H
    DD    04H
    DD    05H
    DD    06H
    DD    07H
    DD    08H
    DD    09H
    ORG $+4007964
[email protected]@3NA DQ    04059000000000000r        ; 100    ; dbB
_DATA    ENDS
PUBLIC    _main