1、程序的段
程序由不同的段構成(代碼段,數據段)
- 程序的靜態特徵就是指令和數據
- 程序的動態特徵就是執行指令處理數據
程序文件的一般佈局
程序文件未運行時
代碼段(.text)
- 源代碼中的可執行語句編譯後進入代碼段
- 代碼段在有內存管理單元的系統中具有只讀屬性
- 代碼段的大小在編譯結束後就已經固定(不能動態改變)
- 代碼段中可以包含常量數據(如:常量字符串)
數據段(.data,.bss,.rodata)
- 數據段用於存放源代碼中具有全局生命期的變量
★ .bss:存儲未初始化(初始化爲0)的變量
★ .data:存儲具有非0初始值的變量,有時也會將字符串常量放這裏
★ .rodata:存儲const關鍵字修飾的變量,字符串常量
注:.bss段只是爲未初始化的全局變量和局部靜態變量預留位置而已,它並沒有內容,所以它在文件中不佔空間
面試中的小問題
同是全局變量和靜態變量,爲什麼初始化的和未初始化的保存在不同段中?
答:程序加載後,.bss段中的所有內存單元被初始化爲0,將程序文件中.data段相關的初始值寫入對應內存單元
編程實驗
關鍵段的分析 test.c
int dt_main()
{
return 0;
}
char g_no_value;
int g_value = 1;
char g_str[] = "wss";
const int g_c = 3;
int dt_main()
{
static char c_no_value;
static int c_value = 2;
return 0;
}
通過objdump,可以看到.data段對應變量的值
2、堆、棧、內存映射段
程序中的棧
- 程序中棧的本質是一片連續的內存空間
- SP寄存器作爲棧頂“指針”實現入棧操作和出棧操作
棧的深入理解
- 中斷髮生時,棧用於保存寄存器的值
- 函數調用時,棧用於保存函數的活動記錄(棧幀信息)
- 併發編程時,每一個線程擁有自己獨立的棧
程序中的堆(Heap)
- 堆是一片“閒置"的內存空間,用於提供動態內存分配
- 堆空間的分配需要函數支持(malloc)
- 堆空間在使用結束後需要歸還(free)
內存映射段(Memory Mapping Segment)
- 內核將硬盤文件的內容直接映射到內存映射段(mmap)
- 動態鏈接庫在可執行程序加載時映射到內存映射段
- 程序執行時能夠創建匿名映射區存放程序數據
內存映射文件原理簡介
- 將硬盤上的文件數據邏輯映射到內存中(零耗時)
- 通過缺頁中斷進行文件數據的實際載入(一次數據拷貝)
- 映射後的內存的讀寫就是對文件數據的讀寫
地址空間分佈圖
0~0x08048000是操作系統使用的,中間空白區域是因爲堆,棧,內存映射段的起始地址是隨機的(爲了安全)
3、小結
各個段的作用
- 堆棧段在程序運行後才正式存在,是程序運行的基礎
- .bss段存放的是未初始化的全局變量和靜態變量
- .text段存放的是程序中的可執行代碼
- .data段保存的是已經初始化了的全局變量和靜態變量
- .rodata段存放程序中的常量值
程序術語的對應關係
- 靜態存儲區通常指程序中的.bss和.data段
- 只讀存儲區通常指程序中的.rodata段
- 局部變量所佔空間爲棧上的空間
- 動態空間爲堆中的空間
- 程序可執行代碼存放於.text段
小結
- 程序編碼在編譯後對應可執行程序中的不同存儲區
- 程序和進程不同,程序靜態概念,進程是動態概念
- 堆棧段是程序運行的基礎,只存在於進程空間中
- 程序可執行代碼存放於.text段,是只讀的
- .bss和.data段用於保存全局變量和靜態變量