BSS段、数据段、代码段、堆与栈
BSS段:BSS段(bss segment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬于靜態內存分配。
數據段:數據段(data segment)通常是指用來存放程序中已初始化的全局變量的一塊內存區域。數據段屬于靜態內存分配。
代碼段:代碼段(code segment/text segment)通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,并且內存區域通常屬于只讀, 某些架構也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數變量,例如字符串常量等。
堆(heap):堆是用于存放進程運行中被動態分配的內存段,它的大小并不固定,可動態擴張或縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張);當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)
棧(stack):棧又稱堆棧, 是用戶存放程序臨時創建的局部變量,也就是說我們函數括弧“{}”中定義的變量(但不包括static聲明的變量,static意味著在數據段中存放變量)。除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,并且待到調用結束后,函數的返回值也會被存放回棧中。由于棧的先進先出特點,所以棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆??闯梢粋€寄存、交換臨時數據的內存區。
【例一】
用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
??????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卻需要占用,其內容由程序初始化,因此造成了上述情況。
【例二】
編譯如下程序(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?? ??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
?----------------------------------------
通過匯編文件可以看到,數組inbss和indata位于不同的段(inbss位于bss段,而indata位于data段)
若把test.cpp中的indata數組拿掉,查看生成的exe文件的大小,可以發現,indata拿掉之后exe文件的大小小了很多。而若拿掉的是inbss數組,exe文件大小跟沒拿掉時相差無幾。
說明了:
bss段(未手動初始化的數據)并不給該段的數據分配空間,只是記錄數據所需空間的大小。
data(已手動初始化的數據)段則為數據分配空間,數據保存在目標文件中。
總結
以上是生活随笔為你收集整理的BSS段、数据段、代码段、堆与栈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: epoll或者kqueue的原理是什么?
- 下一篇: WinCE中命令行工具cvrtbin简介