文章目錄
- gcc如何完成
-
- (1)預處理(進行宏替換)
- (2)編譯(生成彙編)
- (3)彙編(生成機器可識别代碼)
- (4)連結(生成可執行檔案或庫檔案)
- 重要概念:函數庫
-
- gcc如何連結函數
- 靜态庫與動态庫
- file指令與ldd指令
gcc如何完成
格式: gcc [選項] [要編譯的檔案] [選項] [目标檔案]
(1)預處理(進行宏替換)
- 預處理功能主要包括宏定義,檔案包含,條件編譯,去注釋等。
- 預處理指令是以#号開頭的代碼行。
- 執行個體:
gcc –E hello.c –o hello.i
- 選項
,該選項的作用是讓 gcc 在預處理結束後停止編譯過程。-E
- 選項
是指目标檔案,-o
檔案為已經過預處理的C原始程式.i
(2)編譯(生成彙編)
- 在這個階段中,gcc 首先要檢查代碼的規範性、是否有文法錯誤等,以确定代碼的實際要做的工作,在檢查無誤後,gcc 把代碼翻譯成彙編語言。
- 使用者可以使用
選項來進行檢視,該選項隻進行編譯而不進行彙編,生成彙編代碼。-S
- 執行個體:
gcc –S hello.i –o hello.s
(3)彙編(生成機器可識别代碼)
- 彙編階段是把編譯階段生成的
檔案轉成目标檔案.s
- 讀者在此可使用選項
就可看到彙編代碼已轉化為-c
的二進制目标代碼了.o
- 執行個體:
gcc –c hello.s –o hello.o
由于是二進制檔案,一般的打開方式會是以會亂碼。
使用指令
od hello.o | less
即可查閱二進制檔案。
(4)連結(生成可執行檔案或庫檔案)
- 在成功編譯之後,就進入了連結階段。
- 執行個體:
gcc hello.o –o hello
重要概念:函數庫
gcc如何連結函數
- 我們的C程式中,并沒有定義
的函數實作,且在預編譯中包含的printf
中也隻有該函數的聲明,而沒有定義函數的實作,那麼,是在哪裡實作stdio.h
函數的呢?printf
- 最後的答案是:系統把這些函數實作都被做到名為 libc.so.6 的庫檔案中去了,在沒有特别指定時,gcc 會到系統預設的搜尋路徑 /usr/lib 下進行查找,也就是連結到 libc.so.6 庫函數中去,這樣就能實作函數printf了,而這也就是連結的作用
靜态庫與動态庫
- 靜态庫是指編譯連結時,把庫檔案的代碼全部加入到可執行檔案中,是以生成的檔案比較大,但在運作時也就不再需要庫檔案了。其字尾名為
。輸入.a
,采用靜态連結gcc hello.c -o hello -static
- 動态庫在編譯連結時并沒有把庫檔案的代碼加入到可執行檔案中,而是在程式運作時由運作時連結檔案加載庫,這樣做可以節省系統開銷。動态庫字尾名一般為
在編譯時預設使用動态庫,完成連結之後,就生成了可執行檔案。.so,gcc
動态連結形成的程式體積較小,比較節省資源,但是一旦庫丢失,程式就不可以運作了;而靜态形成的程式的體積很大,但具有獨立性,即便庫丢失,也不影響程式運作。
file指令與ldd指令
file
是一個檢視檔案類型的指令,如下:
我們可以看到這個檔案是一個elf形式的可執行程式,64位,平台為x86,與本部落格契合的是它是一個動态連結,那麼所對應的就是利用了動态庫。
ldd
是可以檢視一個可執行程式所依賴的庫是靜态庫還是動态庫。
主要關注這一行,即libc.so.6 => /lib64/libc.so.6
一般來說,我們庫的字首lib以及字尾.so.6(.a)删除這些,餘下的即為語言類型,很顯然,這裡所用的是c語言的庫函數。