在 UNIX/Linux 系統中,編譯鏈接產出的可執行文件多採用 ELF(Executable and Linkable Format) 格式。早期 `a.out` 曾是組譯器輸出,現則為鏈接器輸出的統稱。可通過 `file` 指令確認:
$ file hello.ko
hello.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped
使用 `size` 指令可查看三段大小:
$ size hello.ko
text data bss dec hex filename
224 300 0 524 20c hello.ko
| 段名 | 別名 | 存放內容 | 備註 |
|---|---|---|---|
| .text | 代碼段/文本段 | 可執行指令 | 只讀,多進程共享 |
| .data | 數據段 | 已初始化的全局/靜態變量 | 讀寫,佔用文件空間 |
| .bss | BSS段 | 未初始化的全局/靜態變量 | 僅記錄大小,文件不佔空間,載入時清零 |
以簡單內核模組 `hello.ko` 為例:
text=224, data=300, bss=0int i; int m=2; static int j; static int n=1; 後:text=224, data=300, bss=8觀察發現:
高地址 ┌─────────────────┐ │ 堆棧段 │ ← 向下增長,存局部變量、參數、返回地址 │ ↓ │ │ 空洞 │ ← 未映射區,捕獲空指針訪問 │ ↑ │ │ 堆段 │ ← 向上增長,動態分配 ├─────────────────┤ │ .bss 段 │ ← 緊接 .data,載入時清零 ├─────────────────┤ │ .data 段 │ ← 已初始化全局/靜態變量 ├─────────────────┤ │ .text 段 │ ← 只讀代碼 ├─────────────────┤ │ a.out 魔數等 │ └─────────────────┘ 低地址(前幾 KB 未映射)
載入器利用 mmap() 將各段映射至虛擬地址空間,.text/.data 直接映射文件內容,.bss 僅預留大小並清零。
理解段機制有助於: