在上一篇文章中,我們熟悉了可重定位文件和可執行文件,我們繼續學習連節操作的具體步驟---「符號解析」
連結的過程就是把多個不同的 obj file 相互"黏"在一起,為了使不同的 obj file 能夠相互黏合,必須有固定的規則才行,才能避免連結的過程中不同變數和函數之間的混淆,在連結中,我們將函數很變數稱為符號(Symbol),連結過程中很關鍵的一個部份就是符號的管理,每一個 obj file 都會有一個相對應的符號表(Symbol Tabel) ,記錄著目標文件中所用到的所有符號,每個定義的符號都有一個對應值,稱為Symbol Value,對於variable和functoin來說,Symbol Value指的就是他們的地址。
符號解析到底做了什麼?
下面將使用一個具體的例子介紹符號的類型:
// main.c
int buf[2] = {1, 2};
void swap();
int main() {
swap();
return 0;
}
// swap.c
extern int buf[];
int *bufp0 = &buf[0];
static int *bufp1;
void swap() {
int temp;
bufp1 = &buf[1];
temp = *bufp0;
*bufp0 = *bufp1;
*bufp1 = temp;
}
全局符號 (Global symbols) :
外部符號 (External symbols):
局部符號 (Local symbols):
※函數中的區域變數比如 temp 是存在 stack 中的,編譯器管不到。
首先通過命令
$ gcc -c main.c -o main.o 在通過
$ readelf -s main.o 看符號表:
在編譯階段, Compiler 會將每個 symbol 分類為 strong 或 weak
Linker 利用以下列規則來決定如何做 Linking :
舉一個例子(規則二)
/* foo4.c */
#include <stdio.h>
void f(void);
int x ; // Weak Symbol
int main(){
f();
printf("x = %d\n", x);
return 0;
}
/* bar4.c */
int x; // Weak Symbol
void f(){
x = 15212
}
foo4.c x 被弱定義一次,bar4.c x 也被弱定義一次,因此會任意選擇一個定義,造成難以察覺的錯誤。
深入理解计算机系统
程式設計師的自我修養