鏈結是將各種**和資料片段收集起來組合成為乙個單一檔案的過程。可能發生在編譯、載入到記憶體、程式執行時候。
首先使用預編譯器將mian.cpp翻譯成main.i(ascii碼的中間檔案),再使用編譯器翻譯成main.s(彙編檔案),再使用彙編器翻譯成可重定位目標檔案main.o,最後使用鏈結器將main.o和sum.o鏈結成可執行檔案。最後使用載入器把生成的可執行檔案載入到記憶體中。
**目標檔案:**每個目標檔案的位址都從0開始,相當於每個section的位址是相對於該目標檔案的起始位置的偏移
1)可重定位目標檔案:包含二進位制**和資料,可在編譯的時候與其他可重定位目標檔案合併,生成可執行目標檔案
2)可執行目標檔案:包含二進位制**和資料,可以被複製到記憶體中執行
3)共享目標檔案:特殊的可重定位目標檔案,可以在載入或者執行的時候加載入記憶體中鏈結
這三種檔案具有統一的格式:
elf header:生成該檔案的字的大小,位元組順序,檔案的型別,作業系統的型別、程式入口點;
segment header table:**段在記憶體中的位置
text:被編譯的**塊,函式,二進位製碼
rodata section:唯讀資料部分,const修飾的變數,以及字串常量
data:初始化的全域性變數,大小為儲存的變數大小之和,兩個int為8個位元組
bss:未初始化的全域性靜態變數,不佔據實際的磁碟空間,只在段表中記錄大小,在符號表中記錄符號,當檔案載入執行時,才分配空間以及初始化
symtab:符號表,只會為靜態區域性變數、全域性變數和函式定義符號,不包含非靜態區域性變數,這些存在棧中,編譯器和彙編器一起建立,主要包含了符號的名字和值(位址),如果之後有乙個同名的符號引用則會使用該位址
rel.txt和txt.data:重定位資訊
section header table:所有section的資訊,名字,長度,偏移
common:未初始化的全域性變數,因為可能其他檔案進行了初始化,因此編譯器交給了鏈結器來完成
1)空間與位址分配:掃瞄所有的輸入目標檔案,獲得各個section長度、位置,將符號表統一放到乙個符號表中,同時將同型別的section合併,確定每個section的偏移,每個符號有對應的偏移,這樣就能計算每乙個符號的虛擬位址
2)符號解析和重定位:鏈結器會去全域性符號表找到相對應的符號,將每個引用符號進行位址修改(重定位表記錄了哪些指令需要被重定位),採用絕對位址和相對位址的方法。
一、符號解析:
符號:
1)全域性符號:在當前模組中定義,且可以被其他模組引用
2)外部符號:全域性符號的一種,是在其他模組中定義。
3)本地符號:在當前模組中定義,並且只能由當前模組引用,靜態全域性變數,靜態區域性變數
如果定義了兩個同名的靜態變數
1)在同乙個檔案中定義了兩個同名靜態變數,會有不同的符號定義。
2)在不同的檔案中定義了兩個同名全域性,會根據是否初始化分配強弱符號(已經初始化的變數、函式為強符號,沒有初始化的為弱符號),編譯器編譯的時候會把強弱符號傳遞給彙編器,彙編器會把這些符號包含在可重定位目標檔案的符號表中
i)不能同時出現同名強符號,會出現鏈結錯誤
ii)同名強符號和弱符號,會選擇強符號
iii)多個弱符號,會選擇所佔記憶體最大的乙個
首先會定義3個集合,包含目標檔案的集合e,引用但沒有定義的符號集合u,有定義的符號集合d。
1)如果是可重定位檔案,直接加入e,並且修改u和e
2)如果是linux下的存檔檔案(相當於靜態庫),判斷該檔案中有沒有定義u中的符號,有的話加入e,並修改u和d;如果該檔案**現了未被引用的符號的定義,則會報錯。因此編譯命令包含符號引用的檔案應該在前面,比如mian中呼叫了sum,則main.o在sum.o前面
如果最後u非空則會出現錯誤
二、可執行目標檔案:
elf頭部:存在程式入口點,即第一條指令的位址。載入器會把這個檔案的**和資料部分載入到記憶體裡面,然後跳轉到程式入口點
三、動態鏈結
動態庫可以在可執行檔案載入到記憶體或者執行的時候進行鏈結。
第一步的鏈結會把.so檔案裡的符號表等資訊複製過去。
第二步的鏈結會把.so裡的**段和資料段載入到乙個記憶體上,然後對可執行檔案進行重定位。
深入理解計算機作業系統(2 2 4)
在c語言中,對於有符號數和無符號數之間的轉換是從位級的角度來考慮的而不是從數級的角度來考慮的。簡單說就是,對於有符號數和無符號數之間的轉換,我們希望的是在可以表示的範圍內,數值表示不變,但是c語言中,是二進位制位不變,改變解釋二進位制位的方式。舉例 乙個8位的無符號數128,二進位制位是100000...
深入理解計算機作業系統(三)
基本資料型別 大小端模式 整型數範圍與c標準 複合型型別轉換 從short到unsigned 讓我們複習一下c語言中基本資料型別的位元組數 名稱32位 64位char11 short int22 int4 4long int48 long long int88 char 48 float44 dou...
深入理解計算機作業系統(九)
本文將介紹儲存器層次結構以及區域性性對程式效能的影響。什麼是儲存器層次結構?區域性性 這個詞大家也許並不陌生,計算機中的儲存器從暫存器 快取到記憶體 硬碟,形成了乙個層次結構。為什麼不用單一的一種儲存裝置,比如只用硬碟呢?因為每一種儲存裝置都有它的優缺點,硬碟雖然儲存空間大,但傳輸速率太慢,完全跟不...