程序員自我修養第三章__鏈接.

程序員自我修養第四章讀書筆記

一,靜態鏈接:

鏈接就是將幾個輸入的目標文件加工合併成一個輸出文件,加工合併的方法是將幾個輸入文件中相似的段合併,比如將所有輸入文件的“.text”合併到一個輸出文件的“.text”段。

現在連接器一般將整個鏈接過程分爲兩步:

1,空間與地址的分配,掃描所有輸入的目標文件,獲得它們各個段的長度和屬性,位置,並且將輸入目標文件中所有的符號(Symbol)定義和符號引用收集起來,統一放到一個全局符號表中,這一步連接器能夠獲得所有輸入目標文件的段長度,並且將它們合併,計算出輸出文件中各個段合併後的長度和位置,並且建立映射關係。
2,符號解析與重定位,使用第一步收集的所有信息,讀取輸入文件中段的數據,重定位信息,並且進行符號解析與重定位,調整代碼中的地址等等。

比如有兩個目標文件分別爲a.o和b.o。使用如下命令將這兩個輸入目標文件鏈接成可執行文件ab,其中-e main表示的是main()函數作爲程序的入口,ld連接器默認的程序入口是_start。   ld a.o b.o -e main -o ab

在linux下elf可執行文件的入口地址是0x08048000,由於各個目標文件中的符號相對於起始地址的偏移已經確定,所以鏈接的過程就是將各個目標文件的符號的便宜加上入口地址0x08048000。

符號解析與重定位:目標文件中有重定位表相關的段,比如代碼段.text如有要被重定位的地方,那麼會有一個相應叫.rel.text的重定位段,重定位表的數據結構是struct Elf32_Rel.


二:動態鏈接

動態鏈接:等程序運行的時候才進行連接,這是動態鏈接的基本思想。動態鏈接是把程序按照模塊拆分成各個相對獨立的部分,在程序運行時纔將他們鏈接在一起形成一個完整的程序。程序與動態庫文件的鏈接是由動態鏈接器來完成的,編譯動態庫文件(.so)的命令: gcc -shared -o lib.so lib.c
linux下的動態連接器是ld-2.6.so,共享對象(.so)的最終裝載地址在編譯的時候是不確定的,而是在裝載的時候裝載器根據當前地址空間的空閒情況,動態分配一塊足夠大小的虛擬地址空間給相應的共享對象。
動態鏈接的相關結構:
在動態鏈接情況下,操作系統在裝載完可執行文件之後不能直接將控制權交給可執行文件,因爲可執行文件依賴很多的共享對象,所以此時可執行文件裏對於很多的外部符號引用還處於無效的狀態,所以操作系統在映射完可執行文件之後會先啓用一個動態連接器,在linux平臺下動態連接器ld.so也是一個共享對象,操作系統同樣通過映射的方式將其加入到進程地址空間,操作系統加載完連接器後就將控制權交給動態連接器的入口地址(與可執行文件一樣,動態連接器也有入口地址)。
可執行文件(elf)中的.interp段指定了當前可執行文件用到的動態連接器的位置,比如爲/lib/ld-linux.so.2,可以通過readelf -l a.out | greap interpreter命令來查看。
可執行文件的.dynamic段保存了動態連接器所需要的基本信息,比如依賴哪些共享對象,動態鏈接符號表的位置,動態鏈接重定位表的位置,該結構名字是Elf32_Dyn,定義在elf.h文件中。爲了表示動態鏈接很多模塊之間的符號導入導出關係,ELF專門有一個叫做動態符號表的段用來保存這些信息,這個段名字叫做.dynsym


三:鏈接腳本

由於bootloader 有些驅動等不能使用系統默認的ld連接器,所以需要自己編寫相應的鏈接腳步。


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