gcc a.c 究竟經歷了什么?
掃描二維碼
隨時隨地手機看文章
你知道一次gcc命令究竟經歷了什么嗎?
我們先來看一段C語言示例源代碼:
// test.cc
int main() {
printf("Hello 程序喵\n");
return 0;
}
編譯運行
gcc test.cc
./a.out
Hello 程序喵
如圖一,
gcc構建過程分解
我們平時都會使用gcc來編譯程序,這一行簡單的命令其實經歷了很多復雜的過程:
預處理
編譯
匯編
鏈接
首先使用file看一下test.cc文件類型:
$ file test.cc
test.cc: C source, UTF-8 Unicode text, with CRLF line terminators
我們接下來看看這每個過程都做了什么?
預處理
命令:
gcc -E test.cc -o test.i
或者
cpp test.cc -o test.i
再看下test.i的文件類型
$ file test.i
test.i: C source, UTF-8 Unicode text
這里可以看出預處理后的文件和預處理前的文件類型是相同的,都是文本文件,也可以直接查看test.i的內容,里面代碼較多,就不貼上來了。
其實預處理主要操作有這幾個:
展開所有#define宏定義,進行文本替換
刪除程序中所有的注釋
處理所有的條件編譯,#if、#ifdef、#elif等
處理所有的#include指令,把這些頭文件的內容都復制到引用的源文件中
添加行號和文件名標識,方便編譯器產生警告及調試信息
保留所有的#pragma編譯器指令,因為編譯器會使用他們
編譯
命令:
gcc -S test.cc -o test.s
再查看文件類型
$ file test.s
test.s: assembler source, ASCII text
編譯過程分解
如圖二,編譯過程就是把預處理后的文件進行一系列操作生成相應的匯編文件:
詞法分析:又稱詞法掃描,通過掃描器,利用有限狀態(tài)機的算法將源碼中的字符串分割成一系列記號,如加減乘除數(shù)字括號等。
語法分析:使用語法分析器對詞法分析產生的記號運用上下文無關語法的手段進行語法分析,產生語法分析樹。這期間如果表達式不合法(括號不匹配等),就會報錯。
語義分析:語法分析檢查表達式是否合法,語義分析檢查表達式是否有意義,如浮點型整數(shù)賦值給指針,編譯器就會報錯。
中間語言生成:做一些語法樹優(yōu)化,如6+2=8。
目標代碼生成及優(yōu)化:將中間代碼生成目標匯編代碼。
匯編
命令:
gcc -c test.s -o test.o
或
as test.s -o test.o
查看文件類型:
$ file test.o
testt.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
使用匯編器將匯編代碼轉成機器可以執(zhí)行的指令,其實就是將匯編指令和機器指令按照對照表一一翻譯。
鏈接
為什么匯編器不直接生成可執(zhí)行文件而是生成一個目標文件呢,因為一個文件需要依賴其它好多個庫,這些庫的符號需要通過鏈接過程才可以互相配合生成一個可執(zhí)行文件,需要經歷地址和空間分配、符號決議、重定位等步驟,這塊內容較多,后續(xù)會詳細介紹,現(xiàn)在我們可以簡單的通過ldd查看一下可執(zhí)行程序需要依賴的庫,這些庫都需要在鏈接過程中被鏈接才可以使用。
$ ldd a.out
linux-vdso.so.1 (0x00007ffff5b4a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa1fc660000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa1fce00000)
參考
程序員的自我修養(yǎng)——鏈接、裝載與庫
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!