基本修養實戰篇(四) 鏈接的符號解析與重定位


這次我們來看一個新的例子

a.c的內容如下:

extern int shared;

int main()
{
    int a = 10;
    swap(&a, &shared);
}

b.c的內容如下:

int first_var = 2;
int
shared = 1; void swap(int* a, int* b) { int tmp; tmp = *a; *a = *b; *b = tmp; }

gcc -c a.c -o a.o

gcc -c b.c -o b.o

回顧之前的內容,我們先看一下a.o中的符號表:

readelf -a a.o

 

 Bind類型為LOCAL的,我們都不需要看了,重點看3個GLOBAL的,其中main的Ndx不是UND

而是1,是啥意思來着。是指這個symbol所在段在段表中的索引為1,也就是text段

 

 看到swap和shared是NOTYPE,也即未知類型的全局符號。

然后main的size是56指的是函數指令所占的字節數,Value表示該符號相對於代碼段的起始位置的偏移量

readelf -a b.o

 

 b.o中的shared 符號,在data段中偏移4個字節的位置,swap的size是76

我們是用鏈接器ld把a.o和b.o鏈接起來:

ld a.o b.o  -e main -o ab:

-e: 表示將main做為程序入口,默認的入口是_start

鏈接完成后輸出ab, 我們執行了一下ab, 發現產生了段錯誤,crash了。

但是我用gcc a.c b.c -o ab1, 卻能夠正常運行,比較兩個輸出文件的size, ld鏈接的結果只有1224字節,但是gcc的輸出結果卻有8220字節,讓人不禁再次陷入了深思。為什么會crash, 以及鏈接后的結果為什么相差這么大,我們繼續往下分析。

 

ulimit -c unlimited命令,開啟core dump功能,並且不限制生成core dump文件的大小

 

我們這個調試的問題,后面再詳細說,這里繼續分析一下鏈接的相關問題

 

 首先看一下38 + 4C = 0x84, 不錯,text段的確被合並了。

然后看一下ab中的text的VMA和LMA, 現在有了具體的值,變成了0x00010094,

VMA表示這個段在內存中的運行地址,LMA表示這個text段的加載地址。

也就是說這段代碼映像會被先加載到LMA, 然后運行前還要拷貝到VMA處(如果VMA不等於LMA的話)

【上述結論結合bootloader的相關知識點學習】

那么還有一個問題,為啥text段會被分配到0x00010094,data分配到0x00020118呢?

這涉及到操作系統的進程虛擬地址空間分配的規則。

就是在ld腳本中啦,ld腳本就規定程序和數據在bin文件里面是什么存儲的,以及運行時在rom和ram中是怎么存儲的文件。

這里就引入了鏈接腳本的概念,同時也是bootloader中會涉及到的概念,也就是說就是鏈接腳本中指定的這個地址。

 

ldd --help 中有一個-T 選項,就是讀取鏈接腳本的,也驗證了我們的說法

 

鏈接器在掃描和分配空間完成之后,會根據鏈接腳本中指定的位置,把對應的text和data段放上去。同時因為各個符號在段內的相對位置是固定的,這樣只要給每個符號加上一個 相對text段首大偏移 + 自己所在段的偏移就可以得到每一個符號的絕對地址

 

比如,swap的地址就是 main + 0x38, 也就是 10094h + 38h  = 100cc h


 

在完成空間和地址的分配步驟以后,鏈接器就進入了符號解析與重定位的步驟。

我們先使用objdump -d a.o 看一下在編譯期間,編譯器對外部符號的處理

 

 首先可以看到,main的起始地址是0, 只有等到空間分配完成后,各個函數才會確定自己在虛擬地址空間中的位置

 

然后是bl跳轉語句。關於bl指令,我目前沒有仔細研究。我們重點對比,ab中的這個地方,就知道,對應的地址被修改了。

為了輔助鏈接器完成這個功能,在elf中還有一個叫重定位表的東西,我們在前面提起過.rel.text 和 .rel.data的段就是重定位表,也叫

重定位段。

 

objdump -r a.o

 

 這個命令可以查看a.o中所有需要重定位的地方。

首先指明下面的待重定位符號在text段中,偏移為0x20的地方需要對一個叫swap的符號進行重定位,偏移為0x34的地方需要對shared這個符號

重定位。 與反匯編的代碼段對照一下就可以看的更加清晰

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM