目標文件格式 (Object file)
以文件的方式放在磁碟(Disk)中的 Object module 有三種形式
- 可重定位目標文件 (Relocatable Object File)
- 這類文件包含了二進制程式碼和數據,其形式可以再編一時與其他可重新店為目標文件合併起來,建立一個可執行的目標文件
- 可執行目標文件 (Executable Object File)
- 包含二進制程式碼和數據,其形式可以直接複製到記憶體並執行
- 共享的目標文件 (Shared Object File)
- 一種特殊類型的可重定位目標文件,可在執行時期動態連結並載入到主記憶體,也可在載入到記憶體時期,才動態連結此檔案
目標文件格式
一個程式碼Source code檔案被Compile後,會依照指令和資料部份分開存到Obj File上不同的Section中。
- .text, .bss, .data 是一般編譯器之預設記憶體區段名稱, linker script 會安排實際的記憶體位址給各個區段.
- .text 為唯讀區段, 包含 Const string,及Arm 指令程式(程式碼),安置於ROM
- .data 為可讀寫區段, 放置初值不為 0 的變數 (安置於 RAM中)
- RAM的內容會在斷電、或是系統重置後消失,Reset的程序需從ROM取得data初值(Copy from ROM to RAM)
- .bss 為可讀寫區段, 放置初值為 0 的變數. Reset的程序.bss 區段會被清為 0
- stack 為堆疊區 一般是呼叫函數時的作業區 (返回位址暫存, 傳遞參數, 區域變數和返回值之儲存區), heap 為堆積區 是呼叫 malloc() 時取得記憶區塊的來源.
- symtal 一個符號表,它存放在程序中定義和引用函數和全域變數的訊息
- .rel.text 當Linker 把目標文件和其他文件組合時,需要修改那些 text 的位置(Relocation),可執行文件中並不需要重新為訊息,因此通常會省略
- rel.date 被程序塊引用或定義的所有全域變數的 Relocation 訊息
- .debug 一個除錯符號表 只有以 -g 選項調用編譯器驅動程式時,才會有這個 section
- .strtab 字串表
- .dynamic 動態連結訊息
其他Section(還有很多未被列出)
符號與符號表
連結的過程就是把多個不同的 obj file 相互"黏"在一起,為了使不同的 obj file 能夠相互黏合,必須有固定的規則才行,才能避免連結的過程中不同變數和函數之間的混淆,在連結中,我們將函數很變數稱為符號(Symbol),連結過程中很關鍵的一個部份就是符號的管理,每一個 obj file 都會有一個相對應的符號表(Symbol Tabel) ,記錄著目標文件中所用到的所有符號,每個定義的符號都有一個對應值,稱為Symbol Value,對於variable和functoin來說,Symbol Value指的就是他們的地址。
還存其他幾個不常用到的符號 :
- 全局符號 : 定義在目標文件的全域符號,可被其他 obj file 使用
- 外部符號 : 你有使用,但是卻沒有定義在自己的obj file中 如:printf
- 段名 : 這個符號的值就是該section的start address 如 .text .data
- 局部符號 : 像是static variable, 這類的符號對linker來說意義不大,linker往往忽略他們。
- 行號信息 : obj file 指令與原碼的對應關係,它是可選的
我們可以使用nm指令來查看符號表
連結器如何解析多重定義的全局符號?
在編譯階段, Compiler 會將每個 symbol 分類為 strong 或 weak
Strong Symbol : 包含 procedures 和被初始化過的全域變數。
Weak Symbol : 未被初始化的全域變數。
Linker 利用以下列規則來決定如何做 Linking :
- 同時存在多個同名 strong symbol 是不允許的。
- 假設有一個 strong symbol 與多個 weak symbol , Linker 應選擇 strong symbol。
- 如果只有多個 weak symbol 同名 ,任意選擇其中一個。
Example (規則二)
/* foo3.c */
#include <stdio.h>
void f(void);
int x = 15213; // Strong Symbol
int main(){
f();
printf("x = %d\n", x);
return 0;
}
/* bar3.c */
int x; // Weak Symbol
void f(){
x = 15212
}
$ gcc -o foobar3 foo3.c bar3.c
$ ./foobar3
x = 15212
在運行時,函數 f 將 x 的值由15212改為15212,因為連結器將選擇定義中的 strong symbol
參考文獻
程序員的自我修養-linker
深入理解計算機系統-linker