目標文件(如?.o
?或?.obj
)是編譯器生成的中間文件,其結構遵循?ELF(Linux)或?COFF(Windows)格式。以下是其核心段(Section)和關鍵機制的詳細解析:
1. 目標文件的典型段結構
段名 | 存儲內容 | 作用 |
---|---|---|
.text | 可執行機器指令(函數代碼) | 存放編譯后的二進制指令(如成員函數、靜態函數) |
.data | 已初始化的全局/靜態變量 | 存儲顯式初始化的數據(如?int x = 5; ) |
.bss | 未初始化的全局/靜態變量(清零) | 僅記錄變量大小,不占磁盤空間(運行時由系統初始化為0) |
.rodata | 只讀數據(字符串常量、虛表、RTTI) | 存儲不可修改的數據(如?const char* str = "Hello"; ) |
.symtab | 符號表(函數、變量名及地址) | 記錄符號的元信息,供鏈接器解析跨文件引用 |
.rel.text | 代碼段的重定位信息 | 標記?.text ?中需要修正的指令(如?call ?的目標地址) |
.rel.data | 數據段的重定位信息 | 標記?.data ?中需要修正的指針(如跨文件的全局變量引用) |
.debug | 調試信息(DWARF 格式) | 供調試器使用(如行號、變量類型),發布版可剝離 |
.eh_frame | 異常處理信息(棧展開) | 支持 C++ 異常機制(如?try/catch ) |
2. 符號表(.symtab)詳解
(1) 符號表的組成
符號表記錄所有?函數、全局變量、靜態變量?的信息,每條記錄包含:
-
符號名(如?
_ZN7MyClass8funcEv
,C++ 名稱修飾后的名稱) -
符號值(臨時地址,通常是段內偏移)
-
符號類型(函數?
FUNC
、數據?OBJECT
、未定義?UND
) -
綁定屬性(全局?
GLOBAL
、局部?LOCAL
) -
所屬段(如?
.text
、.data
)
(2) 符號表示例
bash
readelf -s example.o
輸出:
Num: Value Size Type Bind Vis Ndx Name1: 00000000 10 FUNC GLOBAL DEFAULT 1 _ZN7MyClass8funcEv2: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Z3foov
-
Value=00000000
:臨時地址(鏈接后修正)。 -
Ndx=1
:符號屬于?.text
?段(通過節頭表索引確定)。 -
UND
:未定義符號(需鏈接時解析)。
(3) 符號表的作用
-
鏈接階段:解析跨文件引用(如?
main.o
?調用?lib.o
?的函數)。 -
調試階段:映射機器碼到源碼符號(如?
addr2line
?工具)。
3. 重定位表(.rel.text / .rel.data)詳解
(1) 重定位的用途
-
修正代碼段(
.text
)和數據段(.data
)中的?臨時地址,使其指向正確的最終地址。 -
解決跨文件引用問題(如調用其他?
.o
?文件的函數)。
(2) 重定位條目結構
每個條目包含:
-
偏移量(Offset):需修正的指令/數據在段內的位置。
-
類型(Type):如何修正(如絕對地址、相對偏移)。
-
符號(Symbol):目標符號名。
(3) 重定位表示例
bash
readelf -r example.o
輸出:
Relocation section '.rel.text': OFFSET TYPE SYMBOL 00000005 R_X86_64_PC32 _Z3foov
-
OFFSET=0x05
:call
?指令的操作數位于?.text
?段偏移?0x05
?處。 -
TYPE=R_X86_64_PC32
:需修正為?相對地址(目標地址 - 下條指令地址)。 -
SYMBOL=_Z3foov
:修正目標是函數?foo()
。
(4) 重定位過程
-
鏈接器?合并所有?
.text
?段,分配最終地址(如?foo()
?的地址為?0x401200
)。 -
計算修正值:
-
對于?
R_X86_64_PC32
:修正值 = 目標地址(0x401200) - 下條指令地址(0x401005 + 5 = 0x40100A) = 0x1F6
-
-
修改指令:
asm
; 修正前(目標文件) call 0x00000000 ; 修正后(可執行文件) call 0x1F6 ; 實際編碼為 E8 F6 01 00 00
4. 代碼段(.text)與數據段(.data/.bss)
(1) 代碼段(.text)
-
內容:所有函數的機器碼(如?
main()
、MyClass::func()
)。 -
特點:
-
只讀可執行(防代碼注入)。
-
函數調用通過?
call
?指令實現(地址由重定位修正)。
-
(2) 數據段(.data)
-
內容:已初始化的全局/靜態變量(如?
int x = 42;
)。 -
特點:
-
可讀寫,占用磁盤空間(存儲初始值)。
-
加載到內存的?數據段。
-
(3) BSS 段(.bss)
-
內容:未初始化的全局/靜態變量(如?
int y;
)。 -
特點:
-
不占用磁盤空間(僅記錄大小)。
-
運行時由系統初始化為0,加載到內存的?BSS 段。
-
5. 動態鏈接的特殊處理
(1) 全局偏移表(GOT)
-
存儲動態庫中符號的絕對地址(如?
printf
)。 -
首次訪問時由動態鏈接器填充。
(2) 過程鏈接表(PLT)
-
實現?延遲綁定,首次調用函數時觸發動態鏈接器解析地址。
asm
復制
下載
call printf@plt ; 首次調用跳轉到 PLT
6. 關鍵總結
組件 | 作用 | 示例工具命令 |
---|---|---|
.text | 存儲可執行指令(函數代碼) | objdump -d example.o |
.data | 存儲已初始化的全局/靜態變量 | readelf -x .data example.o |
.bss | 存儲未初始化的全局/靜態變量(運行時清零) | size example.o |
.symtab | 記錄符號名、類型、地址(供鏈接器使用) | readelf -s example.o |
.rel.text | 標記代碼段中需要修正的指令(如?call ) | readelf -r example.o |
.rel.data | 標記數據段中需要修正的指針(如跨文件變量引用) | objdump -r -j .data example.o |