深入理解計算機系統系列05

2021-09-28 01:35:45 字數 2935 閱讀 2635

大多數編譯器提供編譯器驅動程式,它代表使用者在需要的時候呼叫語言處理器,編譯器,彙編器,和鏈結器。

它將main.c翻譯成為乙個ascii碼檔案的中間檔案main.i,之後驅動編譯器翻譯器將其翻譯成乙個ascii組合語言檔案,main.s,之後驅動彙編器再將其翻譯成為乙個可重定位的目標檔案main.o,驅動程式以相同的過程生成sum.o,最後執行鏈結器ld,將這些.o檔案組合起來,構成可執行檔案prog(注意shell呼叫作業系統中乙個叫做loader的函式,將prog中的**和資料複製到記憶體中,然後將控制轉移到程式的開頭)

靜態鏈結器,輸入的可重定位的檔案有各種不同的**和資料節(section)組成

鏈結器有兩大重要任務:符號解析和重定位。

目標檔案純粹是位元組塊的集合。

readelf命令可以解析可重定位的目標檔案,可執行的目標檔案,和共享檔案

下面是可重定位的目標檔案

elf頭描述了生成該檔案的系統的字的大小和位元組順序。elf頭剩下的部分包含幫助鏈結器語法分析和解釋目標檔案的資訊。

例如:.text:已編譯程式的機器**

.rodata:唯讀資料

.data:已初始化的全域性和靜態c變數

.bss:未初始化的全域性和靜態c變數

.symtab:符號表

.rel.text:乙個.text節中的位置的列表

.rel.data:被模組引用或者定義的所有全域性變數的重定位資訊

.debug:除錯符號表

.line:原始c源程式中行號和.text節中極其指令的對映

.strtab:乙個字串表

一般用於檢視elf格式的檔案資訊,常見的檔案如在linux上的可執行檔案,動態庫(.so)或者靜態庫(.a) 等包含elf格式的檔案

引數說明

1、選項 -h(elf header),顯示elf檔案開始的檔案頭資訊。

2、選項 -l(program headers),segments 顯示程式頭(段頭)資訊(如果有資料的話)

3、選項 -s(section headers),sections 顯示節頭資訊(如果有資料的話)。

4、選項 -g(section groups),顯示節組資訊(如果有資料的話)

5、選項 -t,section-details 顯示節的詳細資訊(-s的)

6、選項 -s,symbols 顯示符號表段中的項(如果有資料的話)

使用 objdump 檢視目標檔案或者可執行的目標檔案

例子:objdump -d add.o

# objdump -d add.o 

add.o: file format elf32-i386

disassembly of section .text:

00000000 :

0: 55 push %ebp

1: 89 e5 mov %esp,%ebp

3: 8b 45 0c mov 0xc(%ebp),%eax

6: 8b 55 08 mov 0x8(%ebp),%edx

9: 01 d0 add %edx,%eax

b: 5d pop %ebp

c: c3 ret

使用 nm 顯示二進位制目標檔案的符號表,包括符號位址、符號型別、符號名等

例子:nm add.o

# nm add.o

00000000 t add_int

所有的編譯系統提供乙個機制,把所有相關的目標模組打包成乙個單獨的檔案,稱之為靜態庫(static library)

在鏈結的時候,鏈結器將只複製被程式引用的目標模組,這減少了可執行檔案在磁碟和記憶體的空間

在linux系統中,靜態庫以一種稱為存檔(archive)的特殊檔案格式存放在磁碟中,存檔檔案是一組連線起來的可重定位目標檔案的集合

下例:使用ar工具建立靜態庫

中先用gcc編譯了main2.c檔案

而後鏈結,注意,這裡靜態庫要放在最後

-static 告訴編譯器,鏈結器應該構建乙個完全鏈結的可執行目標檔案。

tips:為什麼要把靜態庫放在最後?

這與鏈結器使用靜態庫解析引用的方式有關,即,採用前面無法解釋的符號,放給後面進行解釋,而如果反轉,靜態庫中的符號無法解釋,就會出錯。

首先我們要先明確一下,無論是靜態鏈結和動態鏈結,他們都是鏈結,都不會把庫中其他無用的函式載入進來,而動態鏈結解決的問題是函式重複呼叫,記憶體被重複占用的問題,所以提出了動態鏈結的概念

動態鏈結的步驟中往往有靜態鏈結,只是靜態鏈結生成的部分的可重定位的目標檔案,而剩下的一部分,靠動態鏈結執行時動態載入。因為只是對映和共享,所以可以解決上面的問題。

比如說,f 中有乙個未解析符號 k,如果 d 中存在對它的定義,那麼就可以建立聯絡。如果沒有就放入 u 中。

如果是庫檔案,會試圖把所有 u 中的符號與庫檔案中的符號匹配,匹配上了就從 u 放入 d 中。並把匹配上的模組放入 e 中。一直重複直到 u d 不再變化。庫檔案剩下的內容直接就不管了。

如果往 d 中放入了乙個已經存在的符號或者掃瞄完所有檔案後 u 還是非空,則鏈結器會停止並報錯。否則將 e 中內容經過重定位後合併,生成可執行檔案

ia-32 架構中有兩種重定位的方式,對應著 r_type

r_386_pc32

深入理解計算機系統系列02

深入理解計算機系列02 在 深入理解計算機系統 這本書中,提出了加法逆元的思想,並且輔以乙個習題,我們知道兩數交換的最經典的演算法是三數交換,從計算機的底層實現上看,記憶體與暫存器之間的錯位交換已經是兩數交換的最快演算法了,這本書的習題也提到,上面寫出的加法逆元的兩數交換的演算法本質上並沒有實現出更...

深入理解計算機系統

關鍵路徑是在迴圈的反覆執行中形成的資料相關鏈。迴圈展開是一種程式變換,通過增加每次迭代計算的元素的數量,減少迴圈的迭代次數。重新結合變換能夠減少計算中關鍵路徑上操作的數量,通過更好地利用功能單元的流水線能力得到更好的效能。浮點運算不保證是可結合的,通常迴圈展開和並行地累積在多個值中,是提高程式效能的...

《深入理解計算機系統》

知乎 深入理解計算機系統 這本書需要什麼水平能看懂?15 213 18 218 15 513 introduction to computer systems schedule fall 2016 鏈結失效則 cmu15 213的課程主頁,有ppt,還有錄影,主講人就是這本書的作者。備註 備註 詳細...