前言
如果我們學習過c語言,肯定寫過 hello world這個最簡單的程式。但是從原始檔到可執行程式,中間都經歷了哪些過程呢?下面我們就開始研究一下。
環境搭建
系統:ubuntu 16.04.1 lts
編譯器:gcc
hello.c源程式
#include
//這個乙個注釋
intmain
(void
)
預處理
用gcc來編譯hello.c時,首先是要通過預處理器來處理原始檔,我們開始實操,看看預處理到底做了什麼?
python@ubuntu:~/code$ gcc -e hello.c -o hello.i
python@ubuntu:~/code$ ll hello.i
-rw-rw-r-- 1 python python 17119 6月 26 23:53 hello.i
我們vi hello.i,然後shift+g來到檔案末尾,此時我們看到它去掉了原始檔中的注釋。
我們接著查詢一下printf函式
這下我們就明白了,它把stdio.h標頭檔案的內容複製到了這裡面來,也就是說執行了預處理指令(例如#include #define等等)。編譯
預處理做完以後,此時可以把hello.i編譯成hello.s這個彙編檔案。
python@ubuntu:~/code$ gcc -s hello.i -o hello.s
python@ubuntu:~/code$ cat hello.s
.file "hello.c"
.section .rodata
.lc0:
.string "hello litelefishc"
.text
.globl main
.type main, @function
main:
.lfb0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.lc0, %edi
call puts
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret.cfi_endproc
.lfe0:
.size main, .-main
.ident "gcc: (ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
.section .note.gnu-stack,"",@progbits
彙編
編譯完成以後就可以將組合語言檔案匯編成目標檔案
python@ubuntu:~/code$ gcc -c hello.s
python@ubuntu:~/code$ ls
hello.c hello.i hello.o hello.s
這裡可以使用二進位制工具檢視一下這個目標檔案,在linux系統一般是elf檔案結構。鏈結
最後將生成目標檔案,系統庫的目標檔案,庫檔案進行鏈結,生成乙個可執行程式。
python@ubuntu:
~/code$ gcc hello.o
python@ubuntu:
~/code$ .
/a.out
hello litelefishc
gcc常用選項
-i:包含的標頭檔案的路徑
-l:包含庫檔案的路徑
-l:指定庫名lib***.so
-o:優化選項,1~3越高優先順序越高
-w:警告,all顯示更多的
-c:編譯成.o檔案
-e:輸出到標準輸出,巨集替換,標頭檔案展開
-s:編譯成彙編
-lstdc++:編譯c++**
-o:目標檔案
-g:用於gdb除錯,不加此選項不能用於gdb除錯
總結
gcc編譯過程
本文對gcc編譯器如何工作做乙個概要描述.更為詳細的資訊請參考編譯器手冊。當我們進行編譯的時候,要使用一系列的工具,我們稱之為工具鏈.其中包括 預處理器cpp,編譯器前端gcc g 彙編器as,聯結器ld.乙個編譯過程包括下面幾個階段 1 預處理。預處理器cpp將對原始檔中的巨集進行展開。2 編譯。...
gcc編譯過程
當我們進行編譯的時候,要使用一系列的工具,我們稱之為工具鏈.其中包括 預處理器cpp,編譯器前端gcc g 彙編器as,聯結器ld.乙個編譯過程包括下面幾個階段 1 預處理。預處理器cpp將對原始檔中的巨集進行展開。2 編譯。gcc將c檔案編譯成彙編檔案。3 彙編。as將彙編檔案編譯成機器碼。4 連...
GCC編譯過程
第一步 預處理後結束 引數 e gcc e hello.c o hello.i 檢視hello.i檔案中的內容 cat hello.i stdio.h的內容插入到檔案裡去了,巨集定義也在預處理中都做了相應的處理 第二步 將hello.i 編譯為 目標 引數 c gcc c hello.i o hel...