在徵得作者同意的情況下,本網站的作品允許非盈利性引用,並請註明出處:「作者:luomuxiaoxiao 轉載自:www.luomuxiaoxiao.com"字樣,以尊重作者的勞動成果。版權歸原作者所有。未經允許,嚴禁轉載。


  • 一、生成中間文件
  • 二、可重定位文件分析
    • 2.1 解析文件頭,說明文件構成
    • 2.2 分析ELF文件各部分
      • 2.2.1 ELF header
      • 2.2.2 section headers table及sections
  • 三、參考閱讀

上篇文章我們從整體上介紹了從C文件到可執行文件的編譯過程,並逐個分析了單步編譯時生成的中間文件的類型。為了搞清楚編譯和鏈接過程中主要做了哪些工作, 我們應該首先明白編譯前後,鏈接前後文件內容的改變。根據上篇文章內容,編譯前的文件格式是彙編文件,編譯後的文件是可重定位文件。彙編文件就是簡單的文本文件,而可重定位文件是一個ELF格式的二進位文件。因此,本章我們將從ELF文件格式入手分析可重定位文件的結構。

下面我們以C語言中經典的「hello, world」的產生的可重定位文件為例來說明。使用的環境如下:

  • ubuntu 64位操作系統
  • gcc作為編譯工具(版本信息:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10))

一、生成中間文件

我們依然使用計算機原理系列之三 -------- 如何編譯目標文件中的hello.c文件來研究,使用下列命令生成hello.o:

gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
gcc -c hello.s -o hello.o

二、可重定位文件分析

2.1 解析文件頭,說明文件構成

由於可重定位文件類型是ELF格式(關於ELF文件的知識,請閱讀詳解ELF文件),我們可以使用READELF命令查看其構成。

$ readelf -h hello.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 672 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 13
Section header string table index: 10

其中,我們關注以下欄位:

  1. Type: REL (Relocatable file) : 可以看出.o文件的類型為可重定位文件
  2. Number of program headers: 0:可以看出可重定位文件program header table的長度為0。這是因為program header table保存的是segment信息,而segment是為了給載入器提供可執行程序在載入時所需的信息的,又因為可重定位文件本身並不能直接執行,因此在可重定位文件里不需要program header table
  3. Entry point address: 0x0: 同上,由於可重定位文件不能直接執行,因此其入口地址為0(默認值);
  4. *** of section headers:***:從ELF文件起始地址偏移672個位元組處是section header table的起始地址,section header table中共有13項,每項的大小為64 byte
  5. Size of this header: 64: ELF文件頭大小為64 byte

2.2 分析ELF文件各部分

可重定位文件屬於二進位文件。在linux機器上,可以使用hexdump命令來查看二進位文件的內容。

$ hexdump -C hello.o
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 a0 02 00 00 00 00 00 00 |................|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 0d 00 0a 00 |....@.....@.....|
00000040 55 48 89 e5 bf 00 00 00 00 e8 00 00 00 00 b8 00 |UH..............|
00000050 00 00 00 5d c3 68 65 6c 6c 6f 2c 20 77 6f 72 6c |...].hello, worl|

... snip ...

這實際上就是hello.o文件的實際內容。

註: 最前面一列是hexdump命令添加的,並非ELF文件的內容。它是一個十六進位的數字,表示位元組序號。例如,00000040 55 48 89 e5 bf 00 00 00 00 e8 00 00 00 00 b8 00,其中00000400x40,十進位為64。表示hello.o文件的第64個位元組是『55』 最後一部分由兩個『|』包含的數字和字元也是hexdump命令添加的,它將其左側的十六進位數字轉化成了對應的ASCII字元,所有的控制字元表示為『.』,所有的可顯示字元表示為對應的字元或圖形。

2.2.1 ELF header

根據ELF文件的結構,ELF文件最開始的部分是ELF header,它是一個64位元組大小的結構體,也就是對應了hello.o的前64個字元,即從0000000 - 00000040的部分。前十六個位元組應該是對應其magic number的部分。我們注意到,從0000000 - 0000000F正好就是使用readelf讀出來的magic的值。剩下的部分只要結合struct ElfN_Ehdr的成員信息和hexdump命令輸出的內容即可一一驗證。

*** 請點擊下面鏈接繼續閱讀 ***

計算機原理系列之四 --- 可重定位文件詳解?

luomuxiaoxiao.com圖標

如果你覺得有收穫,請點擊左下角的贊,你的支持是我繼續寫的動力!謝謝!


想第一時間查看我的文章嗎?請關注我的微信公眾號號,搜索「落木蕭蕭技術論壇」,更多精彩文章等你。

微信公眾號


推薦閱讀:
相关文章