链接器(linker)的作用——CSAPP第7章读书笔记
首先說說我為什么要去讀這一章。這個學期開OS的課,在Morden Operating System上讀到和Process有關的內容時看到這樣一句話:“Process is fundamentally a container that holds all the information needed to run a program.”當時瞬間就想到了之前在csapp上看的模棱兩可的“目標可執行文件”這個概念,于是重新又把它的第7章給讀了一遍。
?
要理解linker的作用,首先要搞明白他在整個計算機系統中處于一個什么樣的位置。
關于一個程序是怎樣從碼農們手撕的代碼變成內存中能跑起來的程序這個過程就不再過多的敘述,這篇文章只是著重的去講一下有關linker的這一部分。我們可以看到,linker的接受的輸入是若干個.o文件,簡單的說就是經過匯編器編譯后生成的機器碼,學名叫“relocatable object file(可重定位的目標文件)”,概念相近的稱呼也有“module(模塊)”。而匯編器的輸出,是一個名叫“executable object program(目標可執行文件)”的二進制文件,這個文件的特征就是可以直接拷貝到內存中不需做任何的更改便可以運行。那么我們研究linker的作用是什么就可以從這里入手——為了構造最終的目標可執行文件,他需要對輸入若干可重定位的目標文件做哪些事情?
linker的作用主要有兩個:
(1)符號解析(symbol resolution):將每個符號的定義和每個符號的引用聯系起來。(就是讓系統明白,當這個程序run的時候,遇到的具體的變量或函數名,他們到底來自哪個文件的定義?是自己這個?還是其他一起輸入linker的文件?)
(2)重定位(relocation):把每個符號定義與存儲器中的一個具體位置聯系起來,然后修改所有對這些符號的引用,使得它們指向這個存儲器的位置,從而重定位這些節。(在取得了每個符號的引用和定義的連接之后,要把符號的定義在存儲器中綁定一個具體的地址)
書中對符號的解釋不是太清楚,至少我一開始的時候沒太理解這個概念,在這兒結合書本的內容我用自己的話來概括下我對這個概念的理解。“符號”可以分為3類:
1、由該模塊定義的并且能被其他模塊引用的“全局符號”。這里的“全局符號”對應于C語言中的非靜態的函數和全局變量。
2、由其他模塊定義的由該模塊引用的“全局符號”。解釋同上
3、由該模塊定義的并且不能被其他模塊引用的“全局符號”。對應于C語言中的靜態變量,即static變量。static關鍵字相當于C語言中的“private”,即只能被自己這個文件(模塊)使用的全局變量。
應當注意的是這里的變量全是全局變量而不是函數內部的私有變量,私有變量由運行時stack存儲管理,linker對她并不感興趣:)
?
那么在了解了符號的概念之后,要想具體的了解linker對可重定位的目標可執行文件做的一些事情,就要了解relocatable object file的一些結構(他是怎么記錄自身的各種符號信息的?)對不對?
大家第一次看到這個圖不要害怕,其實這就是匯編器(Assembler)將編譯器處理的源代碼文件進行進一步的編譯或者說匯編之后形成的可重定位的目標可執行文件。這個文件的一個個小格子就是一個個的“節(section)”,他們存放該program的各種信息,在這里我只會解釋幾個我認為對理解linker作用很有必要的section。
.text:已編譯程序的機器代碼。
.data:已初始化的全局C變量。
.bss:未初始化的全局C變量。在這里符號只是一個占位符,它不占用任何的內存空間。
.symtab:一個符號表,存放在程序中定義和引用的函數和全部全局變量的信息。
.rel.test:存放代碼的重定位條目(relocation entry)。
.rel.data:存放數據的重定位條目。
?
以上都屬于本章的基礎知識鋪墊部分,理解了上述內容,就可以很容易的理解linker對可重定位的目標可執行文件所做的操作了。
1、符號解析
linker解析符號的方法是將每個符號的引用與所有輸入的relocatable object file中的.symtab節中所有的符號定義中確定的一個聯系起來。
1.1鏈接器如何解釋多重定義的全局符號?
對于定義和引用都在一個module中的符號,linker的操作很簡單,不需要指來指去改來改去;而真正要深入探討的操作是對定義和引用不在同一個文件中的符號,尤其是當尋找到的符號定義有重名時。對此linker的做法是:
(1)定義強符號和弱符號的概念。函數和已初始化的變量是強符號,為初始化的變量是弱符號。
(2)設定規則。當有多重定義沖突的時候,linker遵循的規則是:
one:不允許有多個強符號定義
two:如果有一個強符號和多個弱符號定義,那么選擇強符號定義
three:如果有多個弱符號定義,那么隨便選擇一個
1.2與靜態庫鏈接
為什么會有“靜態庫”(static libraries)這個概念?
首先在C語言編程中,我們需要實現豐富的功能,就要使用各種各樣的函數接口。以ANSI C為例,它定義了一組廣泛的標準I/O、字符串操作和整數數學函數,例如atoi、printf、scanf、strcpy、rand。他們在libc.a庫中,對每個C程序來說都是可用的。如果不使用靜態庫,我們看看編程開發人員可以用什么其他的辦法來向用戶提供這些函數。
一種實現的方法是讓編譯器直接辨認出對函數的調用,并直接生成相應的代碼——這顯然是不可行的,C語言中有大量的函數,這樣做顯然會使得編譯器的設計變得相當復雜,每次添加、修改、刪除一個函數時,都需要一個新的編譯器版本。雖然對于編程人員而言這樣是十分方便的,因為所有的標準函數都是直接可用的。
另一種實現的方法是將所有的這些函數放到一個單獨的可重定位的目標可執行文件中,它的優點是將編譯器的設計與標準函數的實現分離開來,在一定程度上仍然便利編程人員。但是這樣做的缺點卻是每次運行程序的時候都要將該裝載函數的rof文件copy到內存中去,而這樣是很浪費內存空間的。而且同樣將這么一大批函數賽到一個文件中,每次的維護都要重現編譯整個源文件,這又是相當大的一個工作量。
何為靜態庫?
在Unix中,靜態庫以archive這種特殊的文件格式存在于磁盤中,是一組連接起來的relocatable object file的集合。
1.3鏈接器如何使用靜態庫來解析引用
維護一個基于(U,E,D)三個集合的算法
?
2、重定位
在這個過程中,將合并模塊并為每個符號分配運行時的地址。重定位由兩個步驟組成:
在這里有一個需要理解的概念是重定位條目(relocation entry)。在匯編器生成一個可重定位的目標模塊時,當遇到UNDEFINED的符號,即不知道該數據或代碼最終該存放到存儲器的什么位置時,它就會為該符號生成一個重定位條目,即之前介紹的可重定位目標文件中的.rel.text和.rel.data兩個表所記錄的內容。
轉載于:https://www.cnblogs.com/immortal-worm/p/5819036.html
總結
以上是生活随笔為你收集整理的链接器(linker)的作用——CSAPP第7章读书笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LinkedList模拟队列和堆栈
- 下一篇: 域名解析的记录类型区别