1. 程式人生 > >CSSAPP稀裡糊塗的讀書筆記(七)連結

CSSAPP稀裡糊塗的讀書筆記(七)連結

連結是將各種程式碼和資料片段收集並組合成為一個單一檔案的過程,這個檔案可被載入到記憶體並執行。本章主要講連結的各個方面,不過本章的總結應該會比較少,畢竟連結有連結器自動執行,所以就看個大概吧。

  1. 為了構造可執行檔案,連結器必須完成兩個主要任務:符號解析;重定位。
  2. 目標檔案有三種形式:
  • 可重定位目標檔案。包含二進位制程式碼和資料,其形式可以在編譯時與其他可重定位目標檔案合併起來,建立一個可執行目標檔案。
  • 可執行目標檔案。包含二進位制程式碼和資料,其形式可以被直接複製到記憶體並執行。
  • 共享目標檔案。一種特殊型別的可重定位目標檔案,可以在載入或者執行時被動態地載入進記憶體並連結。
  1. 每個可重定位目標模組m都有一個符號表,它包含m定義和引用地符號的資訊。在連結器上下文中,有三種不同地符號:
  • 由模組m定義並能被其他模組引用地全域性符號。全域性連結器符號對應於非靜態地C函式和全域性變數
  • 由其他模組定義並被模組m引用地全域性符號。這些符號稱為外部符號,對應於在其他模組中定義地非靜態C函式和全域性變數。
  • 只被模組m定義和引用地區域性符號。它們對應於帶static屬性地C函式和全域性變數。這些符號在模組m中任何位置都可見,但是不能被其他模組引用。
  1. 連結器解析符號引用地方法是將每個引用與它輸入地可重定位目標檔案的符號表中的一個確定的符號定義關聯起來。但是對於全域性符號的引用解析就非常棘手。 如果多個模組定義同名的全域性符號,會怎樣? 在編譯時,編譯器向彙編器輸出每個全域性符號,或者是強(strong)或者是弱(weak),而彙編器把這個資訊隱含地編碼在可重定位目標檔案的符號表裡。函式和已初始化的全域性變數是強符號,未初始化的全域性變數是弱符號。 根據強弱符號的定義,Linux連結器使用下面的規則來處理多重定義的符號名:
  • 規則一:不允許由多個同名的強符號。
  • 規則二:如果有一個強符號和多個弱符號同名,那麼選擇強符號。
  • 規則三:如果有多個弱符號同名,那麼從這些弱符號中任意選擇一個。
  1. 一旦連結器完成了符號解析這一步,就把程式碼中的每個符號引用和正好一個符號定義關聯起來。現在就可以開始重定位了。重定位由兩步組成:
  • 重定位節和符號定義。在這一步中,連結器將所有相同型別的節合併為統一型別的新的聚合節。然後連結器將執行時記憶體地址賦給新的聚合節,賦給輸入模組定義的每個節,以及賦給輸入模組定義的每個符號。當這一步完成時,程式中的每條指令和全域性變數都有唯一的執行時記憶體地址了。
  • 重定位節中的符號引用。這一步中,連結器修改程式碼節和資料節中對每個符號的引用,使得它們指向正確的執行時地址。
  1. 載入器將可執行目標檔案中的程式碼和資料從磁碟複製到記憶體中,然後通過跳轉到程式的第一條指令或者入口點來執行該程式。這個將程式複製到記憶體並執行的過程叫做載入。

  2. 共享庫是一個目標模組,在執行和載入時,可以載入到任意的記憶體地址,並和一個在記憶體中的程式連結起來。這個過程稱為動態連結,是由一個動態連結器的程式來執行的。目的是為了解決靜態庫的缺陷——函式程式碼會複製到每個執行程序的文字段中,造成記憶體資源的極大浪費。

只是總結了些概念性的東西,還有很多更詳細的內容,感覺沒有特別的瞭解必要,建議看書自己判斷。