對於編譯原理,如果要系統的學習的話,知識點多的完全可以寫成一本書,推薦大家可以去閱讀一下《編譯原理》這本書,可以全面深入的學習編譯原理,很經典。接下來的文章我僅僅對gcc/g++編譯原理寫一些記錄。
其中gcc命令是對c語言檔案的編譯,g++命令是對c++檔案的編譯,其命令的原理其實是一樣的。
gcc命令編譯一般分為四個步驟及呼叫的命令:
先上乙個醜陋的概念圖
原始檔,以下是hello.c**
#includeint main()
預處理階段主要處理#include和#define,它把#include包含進來的.h 檔案插入到#include所在的位置,把源程式中使用到的用#define定義的巨集用實際的字串代替,刪除注釋。
執行命令,會生成hello.i檔案
$ gcc -e hello.c -o hello.i
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 29 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/_ansi.h" 1 3 4
# 10 "/usr/include/_ansi.h" 3 4
# 1 "/usr/include/newlib.h" 1 3 4
# 14 "/usr/include/newlib.h" 3 4
# 1 "/usr/include/_newlib_version.h" 1 3 4
# 15 "/usr/include/newlib.h" 2 3 4
# 11 "/usr/include/_ansi.h" 2 3 4
# 1 "/usr/include/sys/config.h" 1 3 4
# 1 "/usr/include/machine/ieeefp.h" 1 3 4
# 5 "/usr/include/sys/config.h" 2 3 4
# 1 "/usr/include/sys/features.h" 1 3 4
# 6 "/usr/include/sys/config.h" 2 3 4
# 234 "/usr/include/sys/config.h" 3 4
# 1 "/usr/include/cygwin/config.h" 1 3 4
# 235 "/usr/include/sys/config.h" 2 3 4
# 12 "/usr/include/_ansi.h" 2 3 4
# 30 "/usr/include/stdio.h" 2 3 4
.....此處忽略一千行
# 797 "/usr/include/stdio.h" 3 4
# 2 "hello.c" 2
# 3 "hello.c"
int main()
編譯階段首先檢查**的規範性,語法錯誤,最終把**翻譯成組合語言
執行命令:
$ gcc -s hello.i -o hello.s
以下是生成的hello.s彙編**,有興趣的同學可以研究一下,對於反彙編,這乙份**是必需看懂的^-^。
.file "hello.c"
.text
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.lc0:
.ascii "hello world!\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
leaq .lc0(%rip), %rcx
call printf
movl $0, %eax
addq $32, %rsp
popq %rbp
ret.seh_endproc
.ident "gcc: (gnu) 7.3.0"
.def printf; .scl 2; .type 32; .endef
彙編階段把hello.s檔案翻譯成二進位制機器指令,把hello.s檔案轉換成hello.o檔案,執行命令:
$ gcc -c hello.s -o hello.o
生成的檔案是二進位制格式,普通人是看不懂了,這是乙份讓機器理解的**
當然,我們也可以通過ida,od等工具反彙編得到彙編**
很多人都會認為到了彙編階段產出的.o檔案就可以使用了,當然這個想法是錯誤的,還需要最後乙個階段,就是鏈結階段(linking),可以通俗的理解為關聯系統的api,我們的程式呼叫stdio.h中的printf函式,而這個標準的列印函式是由系統提供的,而鏈結階段就是告訴我們應用呼叫prinft的地方,該去**呼叫這個函式的實現地方,有可能是系統的標準庫函式庫,也有可能是外面提供的函式庫,反正結果就是讓我們的應用知道在**去找到這個函式。
執行命令,最終生成hello可執行的檔案:
$ gcc hello.o -o hello
函式庫一般分為靜態庫和動態庫兩種
文章所有的例子**工程
Linux編譯器 gcc g 使用
gcc是乙個編譯器,將我們寫的高階語言轉化成機器語言 gcc如何完成 格式 gcc 選項 要編譯的檔案 選項 目標檔案 預處理 進行巨集替換 展開所有 gcc e 例 gcc e main.c o main.i o是重新命名,使main.c預處理後生成的檔案名叫main.i 編譯 生成彙編 糾錯,沒...
Linux編譯器 gcc g 使用
gcc 選項 要編譯的檔案 選項 目標檔案 預處理 進行巨集替換 在c語言程式中,並沒有printf函式的定義,stdio.h中也只有該函式的宣告,沒有該函式的實現。系統把這些函式的實現放到指定的庫檔案中例如 libc.so.6,gcc會到系統預設的路徑中進行查詢,這就是連線的作用 建立方法 將包包...
gcc g 命令的經常使用選項
gcc g 命令的經常使用選項格式 選項 解釋 o file 指定輸出檔名稱。在編譯為目標 時,這一選項不是必須的。假設file沒有指定,預設檔名稱是a.out.c 僅僅編譯生成目標檔案,不鏈結 m486 針對 486 進行 優化。o0 不進行優化處理。o 或 o1 優化生成 o2 進一步優化。o3...