gcc 編譯過程

gcc 編譯過程
hello.c hello(a.out)文件, 必須歷經 hello.ihello.shello.o,最後才獲得 hello(
a.out)文件,分別對應着預處理、編譯、彙編和連接 4 個步驟,整個過程如圖 10.5 所示。
編輯器

4 步大體的工做內容以下:
1) 預處理, C 編譯器對各類預處理命令進行處理,包括頭文件包含、宏定義的擴
展、條件編譯的選擇等;
2) 編譯,將預處理獲得的源代碼文件,進行「翻譯轉換」,產生出機器語言的目標
程序,獲得機器語言的彙編文件;
3) 彙編,將彙編代碼翻譯成了機器碼,可是還不能夠運行;
4) 連接,處理可重定位文件,把各類符號引用和符號定義轉換成爲可執行文件中
的合適信息,一般是虛擬地址。
函數

下面根據 hello.c 這個示例,跟蹤一下其中的細節。
1)預處理
gcc 命令加上-E 參數,能夠獲得預處理文件。輸入下列命令:
vmuser@Linux-host:hello$ gcc -E hello.c –o hello.i
將會產生 hello.i 文件,這就是 hello.c 通過預處理後的文件。實際操做結果見圖 10.6

spa

10.6 預編譯獲得 hello.i 文件
一個本來連同空行才 8 行的代碼,通過預處理,獲得了一個 800 多行的預處理文件,文
件開的內容如圖 10.7 所示。
翻譯

10.7 hello.i 文件開頭
hello.i 文件末尾處的內容如圖 10.8 所示。
blog


10.8 hello.i 文件末尾
其他部份內容請用 Vi 打開後進行查看。能夠看到, hello.c 通過預處理後獲得的 hello.i
文件,除了本來的幾行代碼以外,還包含了不少額外的變量、函數等等,這些都是預處理器
處理的結果。
2)編譯
gcc 編譯參數加上-S,能夠將 hello.i 編譯成 hello.s 文件。命令以下:
vmuser@Linux-host:hello$ gcc -S hello.i

md5

實際操做和結果如圖 10.9 所示。

編譯器

10.9 編譯獲得 hello.s 文件
hello.s 是一個彙編文件,可用 Vi 編輯器打開查看,如圖 10.10 所示。
編譯


10.10 hello.s 文件內容
能夠看到,該文件內容都是彙編語句。這裏不對彙編進行解釋。
3)彙編
獲得了彙編文件後,經過 gcc 就能夠獲得機器碼了。在終端輸入下列命令,能夠獲得
hello.o 文件。
vmuser@Linux-host:hello$ gcc -c hello.s
實際操做和結果如圖 10.11 所示。
class


10.11 彙編獲得 hello.o 文件
4)連接
儘管已經獲得了機器碼,但這個文件卻仍是不能夠運行的,必需要通過連接才能運行。
在終端輸入下列命令,將會獲得可執行文件 a.out
vmuser@Linux-host:hello$ gcc hello.o
操做和結果如圖 10.12 所示。
變量


10.12 連接獲得 a.out 文件
a.out gcc 默認輸出文件名稱,能夠經過-o 參數指定新的文件名。例如加上「-o hello
參數,將會生成 hello 文件,這個文件和 a.out 其實是同樣的,用 md5sum 命令計算文件校
驗值,二者徹底同樣,如圖 10.13 所示。


10.13 a.out hello 文件
連接可分爲動態連接和靜態連接:
動態連接使用動態連接庫進行連接,生成的程序在執行的時候須要加載所需的動態
庫才能運行。動態連接生成的程序小巧,可是必須依賴動態庫,不然沒法執行。
Linux 下的動態連接庫實際是共享目標文件(shared object),通常是.so 文件,
做用相似於 Windows 下的.dll 文件。
靜態連接使用靜態庫進行連接,生成的程序包含程序運行所須要的所有庫,能夠直
接運行,不過體積較大。
Linux 下靜態庫是彙編產生的.o 文件的集合,通常以.a 文件形式出現。
gcc 默認是動態連接,加上-static 參數則採用靜態連接。再來看 hello.c 示例,在連接的
時候加上-static 參數:
vmuser@Linux-host:hello$ gcc hello.o -static -o hello_static
操做命令和結果如圖 10.14 所示,能夠看到,動態連接生成的文件大小是 7155 字節,
而靜態連接生成的文件卻有 616096 字節,體積明顯大了不少。


10.14 靜態連接和動態連接結果對比

相關文章
相關標籤/搜索