iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
Arm Platforms

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

Day.6 深入理解連結之重定址

在上篇文章我們說了「符號解析」,符號解析的任務就是:建立定義與引用之間的關聯,而「重定址」的任務就是:把程式碼中每一個符號引用和正好一個符號定義關聯起來。

重定址的流程

  • 合併相同的 section (.data和.text)
  • 對「定義的符號」進行重定址
    • 確定「定義的符號」在虛擬空間的絕對位址,完成這一步以後,每個全域或區域變數都可以確定位置。
  • 對「引用符號」進行重定址
    • 用上述「定義符號」的絕對位置修改.text 和 .data 中「引用符號」的地址。要執行這一步,連結器依賴於可重定址目標模塊中的重定址項(Relocation entries)的資料結構。

連結器是如何完成重定址的?

當程序編譯完成後,組譯產生二進制的可重定址文件,產生的文件包含兩個 Section (上一節有說明)

  • rel.text (函式位置)
  • rel.data (變數位置)

這兩個 Scetion 中 包含了程式碼的重定址項(Relocation entries),其資料結構如下

typedef struct
{
    Elf64_Addr r_offset;    /* Address of reference */
    Elf64_Xword r_info;     /* Symbol index and type of relocation */
} Elf64_Rel;

typedef struct
{
    Elf64_Addr r_offset;    /* Address of reference */
    Elf64_Xword r_info;     /* Symbol index and type of relocation */
    Elf64_Sxword r_addend;  /* Constant part of expression */
} Elf64_Rela
  • r_offset 指出當前需要重定址的位址相對所在的Section起始位置的偏移量。
  • r_info 指出當前的符號在符號表中的索引以及重定址的類型
  • r_addend 一些類型的重定址要使用它對被修改引用的值做偏移調整

在重定址階段,載入器(loader)遍歷所有重定址項並寫入每個 r_offset 指定的位置,視r_info情況選擇 Elf64_RelElf64_RelaElf64_Rel 的符號位址由 r_info 獲得,Elf64_Rela 需從r_info選擇計算公式加 r_addend 獲得。

靜態連結過程

  • 對每一個輸入文件來說,首先判斷是不是Library Files
  • 如果不是Library Files,就是Obj file---${F}$,就能把Obj file放入 ${E}$ 中,根據 ${F}$ 中未解析符號和定義符號判斷後分別放入 ${U}$、${D}$中

※比如說,${F}$ 中有一個未解析符號 ${K}$,如果 ${D}$ 中存在對它的定義,那麼就可以建立聯繫。如果沒有就放入 ${U}$ 中。

  • 如果是Library Files,會試圖把所有 ${U}$ 中的符號與 Library Files 中的符號匹配,匹配上了就從 ${U}$ 放入 ${D}$ 中。並把匹配上的 Module 放入 ${E}$ 中。一直重複直到 ${U}$、${D}$ 不再變化。Library Files剩下的內容直接就不管了。

  • 如果往 ${D}$ 中放入了一個已經存在的符號或者掃描完所有文件後 ${U}$ 還是非空,則連結器會停止並報錯。否則將 ${E}$ 中內容經過重定址後合併,生成可執行文件。

參考資料

深入理解计算机系统
AArch64 relocation prefixes?


上一篇
Day.5 深入理解連結之符號解析
下一篇
Day.7 深入理解動態連結
系列文
30天從0開始探索嵌入式世界15

尚未有邦友留言

立即登入留言