計算機系統篇之鏈接(5):靜態鏈接(下)——重定位

計算機系統篇之鏈接(5):重定位

Author:stormQ

Wednesday, 15. April 2020 04:35PM


重定位的整體過程

重定位的目的是確定每個符號定義的運行時內存地址,並修改對這些符號的引用,使之指向符號定義的運行時內存地址。

重定位的整體過程可以分爲兩個步驟:

  • 重定位節和符號定義。鏈接器將輸入目標文件的相同節合併成一個節,合併的節將作爲可執行目標文件中此類型的節。隨後,鏈接器確定每個合併節的運行時內存地址,並確定合併節中符號定義的運行時內存地址。這一步驟完成後,可執行目標文件中的所有指令和符號定義的運行時內存地址就唯一確定了。

  • 重定位節中的符號引用。鏈接器修改所有的符號引用,使之指向符號定義的運行時內存地址。鏈接器要執行此步驟依賴於目標文件中的重定位信息。

重定位條目

ELF 中的重定位條目分爲兩種格式:RelRela。每個重定位條目表示一個必須被重定位的符號引用,並指明如何計算被修改的符號引用。

查看可重定位目標文件中的重定位信息:

$ readelf -r main.o

Relocation section '.rela.text' at offset 0x208 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000005  000b00000002 R_X86_64_PC32     0000000000000000 _Z4funcv - 4

Relocation section '.rela.eh_frame' at offset 0x220 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0
  • 注:

    • Offset是 Relocation Entry 結構體中的第 1 個字段,佔用 8 字節,表示需要修改的符號引用的位置。對於可重定位目標文件,該字段表示需要修改的符號引用的起始位置在目標 section (.rela.text中的重定位條目對應的目標 section 爲.text.rela.data中的重定位條目對應的目標 section 爲.data,以此類推)中的偏移量(字節)。對於可執行目標文件和可共享目標文件,該字段表示需要修改的符號引用的起始位置所對應的虛擬內存地址。

    • Info是 Relocation Entry 結構體中的第 2 個字段,佔用 8 字節,表示符號表索引和重定位類型(符號表索引佔用高 32 位,重定位類型佔用低 32 位)。

      符號表索引表示需要修改的符號引用在.symtabsection中的索引。這裏的Sym. ValueSym. Name列只是打印了所對應符號表條目中ValueName列的值。

      重定位類型指示鏈接器如何修改該符號引用的值。重定位類型因不同的處理器而異。

    • Addend是 Relocation Entry 結構體中的第 3 個字段,佔用 8 字節,表示一個有符號常數,一些重定位類型要使用它對被修改符號引用的值做偏移調整。

    • 重定位條目RelRela之間的唯一區別:Rel中沒有Addend字段。

源碼:

$ cat test.cpp 
extern int g_val_1;
extern int g_val_2;

void func()
{
  g_val_1 *= 2;
  g_val_2 *= 2;
}

$ cat main.cpp 
int g_val_1;
int g_val_2 = 3;

void func();

int main()
{
  func();
  return 0;
}

1)驗證對於可重定位目標文件,Offset 字段表示需要修改的符號引用的起始位置在目標 section 中的偏移量(字節)

可重定位目標文件main.o中代碼的重定位條目放在.rela.textsection 中。該 section 只包含一個重定位條目,其中Offset字段的值爲 0x5,表示在目標 section (即.text)中起始位置爲 0x5 的內容需要被修改。如果該內容的值在可執行目標文件main中被修改了,即可驗證此結論。

查看可重定位目標文件main.o.textsection:

$ objdump -d main.o

main.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	e8 00 00 00 00       	callq  9 <main+0x9>
   9:	b8 00 00 00 00       	mov    $0x0,%eax
   e:	5d                   	pop    %rbp
   f:	c3                   	retq   

可以看出,main.o.textsection 中偏移量(相對於.text的起始位置,即相對於main函數的起始位置)爲 0x5 的內容的當前值爲 0x0。這裏有兩點需要注意:1)由於偏移量爲 0x5 的位置與下一條指令的開始位置之間有 4 個字節,所以該內容佔用 4 字節;2)由於main.o的字節序是小端,所以,00 00 00 00中最右邊的00對應的地址爲偏移量 0x5。

關注公衆號,即可查看完整內容。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章