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

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

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


10.8 hello.i 文件末尾
其余部分內容請用 Vi 打開后進行查看。可以看到, hello.c 經過預處理后得到的 hello.i
文件,除了原本的幾行代碼之外,還包含了很多額外的變量、函數等等,這些都是預處理器
處理的結果。
2)編譯
gcc 編譯參數加上-S,可以將 hello.i 編譯成 hello.s 文件。命令如下:
vmuser@Linux-host:hello$ gcc -S hello.i

實際操作和結果如圖 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 所示。


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 靜態鏈接和動態鏈接結果對比


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM