iT邦幫忙

2021 iThome 鐵人賽

DAY 5
0
Arm Platforms

30天從0開始探索嵌入式世界系列 第 5

Day.5 深入理解連結之符號解析

在上一篇文章中,我們熟悉了可重定位文件和可執行文件,我們繼續學習連節操作的具體步驟---「符號解析」

符號與符號表

連結的過程就是把多個不同的 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) :

    • 定義在目標文件的全域符號,可被其他 obj file 使用。像是是非 static C函數和非 static 的C全局變數,如:main中的buf。
  • 外部符號 (External symbols):

    • 你有使用,但是卻沒有定義在自己的obj file中 如:printf或是 main.c 中的函數名 swap
  • 局部符號 (Local symbols):

    • 僅由此 module中 定義和引用的符號,像是static variable, 這類的符號對linker來說意義不大,linker往往忽略他們,如:swap.c 中的 bufp1。

※函數中的區域變數比如 temp 是存在 stack 中的,編譯器管不到。

如何查看Obj file 中的符號?

首先通過命令
$ gcc -c main.c -o main.o 在通過
$ readelf -s main.o 看符號表:

  • ‎buf 是屬於第 3(Ndx)節,OBJECT 物件,全域作用域,大小 8位元組。‎
  • ‎swap 不知道是哪個節的,不知道什麼類型,沒有定義的符號(UND),全域作用域‎
  • ‎main 第 1 節(.text)函數物件,大小 25 位元組。‎

連結器如何解析多重定義的全局符號?

在編譯階段, Compiler 會將每個 symbol 分類為 strong 或 weak

  • Strong Symbol : 包含 procedures 和被初始化過的全域變數。
  • Weak Symbol : 未被初始化的全域變數。

Linker 利用以下列規則來決定如何做 Linking :

  • 同時存在多個同名 strong symbol 是不允許的。
  • 假設有一個 strong symbol 與多個 weak symbol , Linker 應選擇 strong symbol。
  • 如果只有多個 weak symbol 同名 ,任意選擇其中一個。

舉一個例子(規則二)

/* 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 也被弱定義一次,因此會任意選擇一個定義,造成難以察覺的錯誤。

tags: IT 鐵人系列文章

參考資料

深入理解计算机系统
程式設計師的自我修養


上一篇
Day.4深入理解連結之Object file
下一篇
Day.6 深入理解連結之重定址
系列文
30天從0開始探索嵌入式世界15

尚未有邦友留言

立即登入留言