BSS段、数据段、代码段、堆与栈
BSS段:BSS段(bss segment)通常是指用來(lái)存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域。BSS是英文Block Started by Symbol的簡(jiǎn)稱。BSS段屬于靜態(tài)內(nèi)存分配。
數(shù)據(jù)段:數(shù)據(jù)段(data segment)通常是指用來(lái)存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配。
代碼段:代碼段(code segment/text segment)通常是指用來(lái)存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于只讀, 某些架構(gòu)也允許代碼段為可寫(xiě),即允許修改程序。在代碼段中,也有可能包含一些只讀的常數(shù)變量,例如字符串常量等。
堆(heap):堆是用于存放進(jìn)程運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段,它的大小并不固定,可動(dòng)態(tài)擴(kuò)張或縮減。當(dāng)進(jìn)程調(diào)用malloc等函數(shù)分配內(nèi)存時(shí),新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張);當(dāng)利用free等函數(shù)釋放內(nèi)存時(shí),被釋放的內(nèi)存從堆中被剔除(堆被縮減)
棧(stack):棧又稱堆棧, 是用戶存放程序臨時(shí)創(chuàng)建的局部變量,也就是說(shuō)我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量,static意味著在數(shù)據(jù)段中存放變量)。除此以外,在函數(shù)被調(diào)用時(shí),其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中,并且待到調(diào)用結(jié)束后,函數(shù)的返回值也會(huì)被存放回棧中。由于棧的先進(jìn)先出特點(diǎn),所以棧特別方便用來(lái)保存/恢復(fù)調(diào)用現(xiàn)場(chǎng)。從這個(gè)意義上講,我們可以把堆棧看成一個(gè)寄存、交換臨時(shí)數(shù)據(jù)的內(nèi)存區(qū)。
【例一】
用cl編譯兩個(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)容由程序初始化,因此造成了上述情況。
【例二】
編譯如下程序(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:產(chǎn)生匯編代碼)
產(chǎn)生的匯編代碼(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?? ??inbss@@3PAHA?? ??? ??? ??? ??? ?; inbss
PUBLIC?? ??fA@@3MA?? ??? ??? ??? ??? ?; fA
PUBLIC?? ??indata@@3PAHA?? ??? ??? ??? ??? ?; indata
PUBLIC?? ??dbB@@3NA?? ??? ??? ??? ??? ?; dbB
_BSS?? ?SEGMENT
?inbss@@3PAHA DD 0f4a10H DUP (?)?? ??? ??? ?; inbss
?fA@@3MA DD?? ?01H DUP (?)?? ??? ??? ??? ?; fA
_BSS?? ?ENDS
_DATA?? ?SEGMENT
?indata@@3PAHA DD 01H?? ??? ??? ??? ??? ?; indata
??? DD?? ?02H
??? DD?? ?03H
??? DD?? ?04H
??? DD?? ?05H
??? DD?? ?06H
??? DD?? ?07H
??? DD?? ?08H
??? DD?? ?09H
??? ORG $+4007964
?dbB@@3NA DQ?? ?04059000000000000r?? ??? ?; 100?? ?; dbB
_DATA?? ?ENDS
PUBLIC?? ?_main
EXTRN?? ?_printf:NEAR
_DATA?? ?SEGMENT
$SG537?? ?DB?? ?'%d ', 00H
_DATA?? ?ENDS
_TEXT?? ?SEGMENT
_run$ = -400
_i$ = -404
_main?? ?PROC NEAR
; File test.cpp
; Line 13
??? push?? ?ebp
??? mov?? ?ebp, esp
??? sub?? ?esp, 404?? ??? ??? ??? ?; 00000194H
??? push?? ?edi
; Line 14
??? mov?? ?DWORD PTR _run$[ebp], 1
??? mov?? ?DWORD PTR _run$[ebp+4], 2
??? mov?? ?DWORD PTR _run$[ebp+8], 3
??? mov?? ?DWORD PTR _run$[ebp+12], 4
??? mov?? ?DWORD PTR _run$[ebp+16], 5
??? mov?? ?DWORD PTR _run$[ebp+20], 6
??? mov?? ?DWORD PTR _run$[ebp+24], 7
??? mov?? ?DWORD PTR _run$[ebp+28], 8
??? mov?? ?DWORD PTR _run$[ebp+32], 9
??? mov?? ?ecx, 91?? ??? ??? ??? ??? ?; 0000005bH
??? xor?? ?eax, eax
??? lea?? ?edi, DWORD PTR _run$[ebp+36]
??? rep stosd
; Line 15
??? mov?? ?DWORD PTR _i$[ebp], 0
??? jmp?? ?SHORT $L534
$L535:
??? mov?? ?eax, DWORD PTR _i$[ebp]
??? add?? ?eax, 1
??? mov?? ?DWORD PTR _i$[ebp], eax
$L534:
??? cmp?? ?DWORD PTR _i$[ebp], 1002000?? ??? ?; 000f4a10H
??? jge?? ?SHORT $L536
; Line 16
??? mov?? ?ecx, DWORD PTR _i$[ebp]
??? mov?? ?edx, DWORD PTR ?inbss@@3PAHA[ecx*4]
??? push?? ?edx
??? push?? ?OFFSET FLAT:$SG537
??? call?? ?_printf
??? add?? ?esp, 8
??? jmp?? ?SHORT $L535
$L536:
; Line 17
??? xor?? ?eax, eax
; Line 18
??? pop?? ?edi
??? mov?? ?esp, ebp
??? pop?? ?ebp
??? ret?? ?0
_main?? ?ENDP
_TEXT?? ?ENDS
END
?----------------------------------------
通過(guò)匯編文件可以看到,數(shù)組inbss和indata位于不同的段(inbss位于bss段,而indata位于data段)
若把test.cpp中的indata數(shù)組拿掉,查看生成的exe文件的大小,可以發(fā)現(xiàn),indata拿掉之后exe文件的大小小了很多。而若拿掉的是inbss數(shù)組,exe文件大小跟沒(méi)拿掉時(shí)相差無(wú)幾。
說(shuō)明了:
bss段(未手動(dòng)初始化的數(shù)據(jù))并不給該段的數(shù)據(jù)分配空間,只是記錄數(shù)據(jù)所需空間的大小。
data(已手動(dòng)初始化的數(shù)據(jù))段則為數(shù)據(jù)分配空間,數(shù)據(jù)保存在目標(biāo)文件中。
總結(jié)
以上是生活随笔為你收集整理的BSS段、数据段、代码段、堆与栈的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: epoll或者kqueue的原理是什么?
- 下一篇: WinCE中命令行工具cvrtbin简介