編碼學習筆記 ——目標文件

參考:《程序員的自我修養》第3章

真正了不起的程序員對自己的程序的每一個字節都瞭如指掌。

學習筆記,我就是個搬運工。
ELF:Executable Linkable Format。
PE-COFF:Portable Executable Common File Format。
查看目標文件內部結構的工具:
objdump -h file.o             // 將elf文件各個段的基本信息打印出來
objdump -x file.o             // 將elf文件各個段的基本信息打印出來,更詳細
objdump -s file.o             // 將段的內容以16進制打印出來
objdump -d file.o             // 反彙編
readelf -h file.o             // 查看elf文件頭信息
readelf -S file.o             // 查看elf文件段表結構
nm file.o                     // 查看elf文件的符號表

查看elf文件代碼段、數據段、BSS長度:
size file.o
1. 什麼是目標文件

源代碼編譯後但未進行鏈接的中間文件,Linux下的.o,Windows下的.obj。
目標文件與可執行文件採用相同的文件格式,主流是Linux爲ELF,Windows爲PE-COFF。
 

2. 可執行文件格式在這裏插入圖片描述
3. ELF文件結構

ELF文件結構大致可分爲ELF文件頭、段表、字符串表、符號表等。

  • ELF頭
    在這裏插入圖片描述
    ELF魔數: ELF頭中的Magic,是ELF魔數,16個字節,對應class到ABI version的內容,用於標識ELF文件的平臺屬性,如ELF字長,字節序,ELF版本等。
    0x7f 45 4c 46:對應的ASCII碼爲 DEL控制符,E,L,F。
    文件類型:系統通過文件類型常量來判斷ELF的真正文件類型,而非後綴名。REL(1)—可重定位文件,EXEC(2)—可執行文件,DYN(3)—共享目標文件。
    機器類型:表示該ELF文件的平臺屬性,即可以在什麼平臺下運行。

  • 段表:描述了ELF文件各個段的信息,如段名、段的長度、在文件中的偏移、讀寫權限等。主要確定段屬性的是段的類型和段的標誌位。
    在這裏插入圖片描述在這裏插入圖片描述
    段類型
    在這裏插入圖片描述
    段標誌位 :表示該段在進程虛擬地址空間中的屬性,可讀可寫可執行,分配空間等。

  • 重定位表:鏈接器在處理目標文件時,需對目標文件中的某些部位進行重定位,即代碼段和數據段那些絕對地址的引用的位置。重定位表裏記錄着這些重定位信息。

  • 字符串表:由於字符串長度不固定,所以用固定結構來表示比較困難,所以把字符串集中起來存放到一個表,用字符串在表中的偏移來引用字符串。
    .strtab :字符串表,保存普通的字符串。
    .shstrtab :段表字符串表,保存段表中用到的字符串,如段名。
     

4. 鏈接

目標文件相互拼合實質是目標文件之間對地址的引用,即對函數和變量地址的引用

  • 符號:函數和變量。
  • 符號名:函數名和變量名。
  • 符號表:每一個目標文件都有一個對應的符號表,記錄了目標文件中用到的所有符號。
  • 符號值:對於函數和變量而言,就是它們的地址。
    在這裏插入圖片描述

ELF符號表結構
在這裏插入圖片描述

  • Num:表示符號表數組的下標。
  • Value:符號值。
  • Size:符號大小。
  • Type:符號類型。NOTYPE,未知類型;OBJECT,數據對象;FUNC,函數或其它可執行代碼;SECTION,段;FILE,文件。
  • Bind:符號綁定信息。LOCAL,局部符號,對目標文件外的符號不可見;GLOBAL:全局符號,外部可見;WEAK:弱引用。
  • Ndx:表示該符號所屬的段。
  • Name:符號名稱。

函數簽名:用於識別不同的函數,包含了函數名、參數類型、所在類、名稱空間及其它。

弱符號和強符號:弱符號和強符號是針對定義來說,而非引用。

  • 編譯器默認函數和已初始化的全局變量爲強符號,未初始化的全局變量爲弱符號。
  • 可用__attributte__((weak))來定義任何一個強符號爲弱符號。
  • 鏈接器處理多次定義的全局符號:
    ❤❤ 不允許強符號被多次定義,即不同的目標文件不能有相同的強符號;如果有,就報錯。
    ❤❤ 如果一個符號在某個目標文件中是強符號,其它是弱符號,那麼選擇強符號。
    ❤❤ 如果一個符號在所有目標文件中都是弱符號,選佔用空間最大的那個。

弱引用和強引用:強引用,鏈接器發現某個符號未定義就會報未定義的錯誤。弱引用,鏈接器發現某個符號未定義不報錯,默認其爲0或者一個特定的值。

  • 可用__attributte__((weakref))來申明對一個外部函數的引用爲弱引用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章