GCC之旅(1)--- GCC的編譯流程

 

參考華清遠見《嵌入式linux應用程序開發詳解》第三章

後綴名的說明:

.i  已經過預處理的C原始程序

.ii  已經過預處理的C++原始程序

.s/.S  彙編語言原始程序

.h  預處理文件(頭文件)

.o  目標文件

.a/.so  編譯後的庫文件

 

GCC編譯流程分爲4個步驟

1.       預處理(Preprocessing)

2.       編譯(Compiling)

3.       彙編(Assembling)

4.       鏈接(Linking)

 

test.c

  1 #include <stdio.h>

  2 int main(void)

  3 {

  4         printf("Hello World!/n");

  5         return 0;

  6 } 

 

 

1.       預處理(Preprocessing:在這個階段GCC將頭文件包含進test.c文件,並生成文件test.i

 

執行下面命令生成test.i

[root@localhost gccinfo]# gcc -E test.c -o test.i

 

test.i的文件內容:

  1 # 1 "test.c"

  2 # 1 "<built-in>"

  3 # 1 "<command-line>"

  4 # 1 "test.c"

  5 # 1 "/usr/include/stdio.h" 1 3 4

  6 # 28 "/usr/include/stdio.h" 3 4

  7 # 1 "/usr/include/features.h" 1 3 4

  8 # 335 "/usr/include/features.h" 3 4

  9 # 1 "/usr/include/sys/cdefs.h" 1 3 4

 10 # 360 "/usr/include/sys/cdefs.h" 3 4

 ………….

750 # 2 "test.c" 2

751 int main(void)

752 {

753  printf("Hello World!/n");

754  return 0;

755 }

 

2.       編譯(Compiling:在這個階段GCC檢查test.i代碼的規範性,確定有沒有語法錯誤。確認無誤後,則把test.i轉化爲彙編代碼文件test.s

執行下面命令生成test.s

[root@localhost gccinfo]# gcc -S test.i -o test.s

test.s的文件內容:

  1         .file   "test.c"

  2         .section        .rodata

  3 .LC0:

  4         .string "Hello World!"

  5         .text

  6 .globl main

  7         .type   main, @function

  8 main:

  9         leal    4(%esp), %ecx

 10         andl    $-16, %esp

 11         pushl   -4(%ecx)

 12         pushl   %ebp

 13         movl    %esp, %ebp

 14         pushl   %ecx

 15         subl    $4, %esp

 16         movl    $.LC0, (%esp)

 17         call    puts

 18         movl    $0, %eax

 19         addl    $4, %esp

 20         popl    %ecx

 21         popl    %ebp

 22         leal    -4(%ecx), %esp

 23         ret

 24         .size   main, .-main

 25         .ident  "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"

 26         .section        .note.GNU-stack,"",@progbits

 

3.       彙編階段(Assembling:在這個階段GCCtest.s文件中的彙編代碼轉化爲目標機器的機器代碼文件test.o,爲二進制文件。

 

執行下面命令生成test.o

[root@localhost gccinfo]# gcc -c test.s -o test.o

 

執行以下命令產看test.o

[root@localhost gccinfo]# od -t c test.o

 

test.o文件內容:

0000000 177   E   L   F 001 001 001  /0  /0  /0  /0  /0  /0  /0  /0  /0

0000020 001  /0 003  /0 001  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0000040 354  /0  /0  /0  /0  /0  /0  /0   4  /0  /0  /0  /0  /0   (  /0

0000060  /v  /0  /b  /0 215   L   $ 004 203 344 360 377   q 374   U 211

0000100 345   Q 203 354 004 307 004   $  /0  /0  /0  /0 350 374 377 377

0000120 377 270  /0  /0  /0  /0 203 304 004   Y   ] 215   a 374 303  /0

0000140   H   e   l   l   o       W   o   r   l   d   !  /0  /0   G   C

0000160   C   :       (   G   N   U   )       4   .   3   .   0       2

0000200   0   0   8   0   4   2   8       (   R   e   d       H   a   t

0000220       4   .   3   .   0   -   8   )  /0  /0   .   s   y   m   t

0000240   a   b  /0   .   s   t   r   t   a   b  /0   .   s   h   s   t

0000260   r   t   a   b  /0   .   r   e   l   .   t   e   x   t  /0   .

0000300   d   a   t   a  /0   .   b   s   s  /0   .   r   o   d   a   t

0000320   a  /0   .   c   o   m   m   e   n   t  /0   .   n   o   t   e

0000340   .   G   N   U   -   s   t   a   c   k  /0  /0  /0  /0  /0  /0

0000360  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

*

0000420  /0  /0  /0  /0 037  /0  /0  /0 001  /0  /0  /0 006  /0  /0  /0

0000440  /0  /0  /0  /0   4  /0  /0  /0   +  /0  /0  /0  /0  /0  /0  /0

0000460  /0  /0  /0  /0 004  /0  /0  /0  /0  /0  /0  /0 033  /0  /0  /0

0000500  /t  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0   X 003  /0  /0

0000520 020  /0  /0  /0  /t  /0  /0  /0 001  /0  /0  /0 004  /0  /0  /0

0000540  /b  /0  /0  /0   %  /0  /0  /0 001  /0  /0  /0 003  /0  /0  /0

0000560  /0  /0  /0  /0   `  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0000600  /0  /0  /0  /0 004  /0  /0  /0  /0  /0  /0  /0   +  /0  /0  /0

0000620  /b  /0  /0  /0 003  /0  /0  /0  /0  /0  /0  /0   `  /0  /0  /0

0000640  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0 004  /0  /0  /0

0000660  /0  /0  /0  /0   0  /0  /0  /0 001  /0  /0  /0 002  /0  /0  /0

0000700  /0  /0  /0  /0   `  /0  /0  /0  /r  /0  /0  /0  /0  /0  /0  /0

0000720  /0  /0  /0  /0 001  /0  /0  /0  /0  /0  /0  /0   8  /0  /0  /0

0000740 001  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0   m  /0  /0  /0

0000760   -  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0 001  /0  /0  /0

0001000  /0  /0  /0  /0   A  /0  /0  /0 001  /0  /0  /0  /0  /0  /0  /0

0001020  /0  /0  /0  /0 232  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001040  /0  /0  /0  /0 001  /0  /0  /0  /0  /0  /0  /0 021  /0  /0  /0

0001060 003  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0 232  /0  /0  /0

0001100   Q  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0 001  /0  /0  /0

0001120  /0  /0  /0  /0 001  /0  /0  /0 002  /0  /0  /0  /0  /0  /0  /0

0001140  /0  /0  /0  /0 244 002  /0  /0 240  /0  /0  /0  /n  /0  /0  /0

0001160  /b  /0  /0  /0 004  /0  /0  /0 020  /0  /0  /0  /t  /0  /0  /0

0001200 003  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0   D 003  /0  /0

0001220 022  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0 001  /0  /0  /0

0001240  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001260  /0  /0  /0  /0 001  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001300 004  /0 361 377  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001320 003  /0 001  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001340 003  /0 003  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001360 003  /0 004  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001400 003  /0 005  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001420 003  /0  /a  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001440 003  /0 006  /0  /b  /0  /0  /0  /0  /0  /0  /0   +  /0  /0  /0

0001460 022  /0 001  /0  /r  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0  /0

0001500 020  /0  /0  /0  /0   t   e   s   t   .   c  /0   m   a   i   n

0001520  /0   p   u   t   s  /0  /0  /0 024  /0  /0  /0 001 005  /0  /0

0001540 031  /0  /0  /0 002  /t  /0  /0  /n

0001551

 

4.       鏈接(Linking:在成功編譯之後,就進入了鏈接階段。在這裏涉及到一個重要的概念:函數庫。重新查看這個小程序時,在這個程序中並沒有定義“printf”的函數實現,且在預編譯中包含進的“stdio.h”中也只有該函數的聲明,而沒有定義函數的實現,那麼,是在哪裏實現“printf”函數的呢?最後的答案是:系統把這些函數實現都被做到名爲 libc.so.6 的庫文件中去了,在沒有特別指定時,Gcc 會到系統默認的搜索路徑“/usr/lib”下進行查找,也就是鏈接到 libc.so.6 庫函數中去,這樣就能實現函數“printf”,而這也就是鏈接的作用。

函數庫一般分爲靜態庫和動態庫兩種。靜態庫是指編譯鏈接時,把庫文件的代碼全部加入到可執行文件中,因此生成的文件比較大,但在運行時也就不再需要庫文件了。其後綴名一般爲“.a” 。動態庫與之相反,在編譯鏈接時並沒有把庫文件的代碼加入到可執行文件中,而是在程序執行時由運行時鏈接文件加載庫,這樣可以節省系統的開銷。動態庫一般後綴名爲“.so”,如前面所述的 libc.so.6 就是動態庫。GCC 在編譯時默認使用動態庫。完成了鏈接之後,GCC 就可以生成可執行文件。

 

執行以下命令生成可執行文件test

[root@localhost gccinfo]# gcc test.o -o test

同時也可以通過od命令產看其內容。

 

以上4個編譯步驟可以一次完成,執行下面命令即可:

[root@localhost gccinfo]# gcc test.c -o test

編譯程序時,gcc會自動幫你連接所有編譯的文件名及標準函數庫. 首先GCC會把所有的原始文件都轉成目標文件,然後會自動調用linker 來連接相關文件名(事實上linker是個文件名爲ld的程序,而不是gcc 本身提供的功能,我們可以說gccld的關係是相當密切的),GG同樣 也知道標準函數庫的位置,並且在調用ld時傳入相關信息。

 

發佈了26 篇原創文章 · 獲贊 9 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章