GCC 編譯全過程

來源:互聯網
上載者:User

現代編譯器常見的編譯過程:
源檔案-->預先處理-->編譯/最佳化-->彙編-->連結-->可執行檔

對於gcc而言:

第一步 預先處理
       命令: gcc -o test.i -E test.c
             或者 cpp -o test.i test.c (這裡cpp不是值c plus plus,而是the C Preprocessor)
       結果:  產生預先處理後的檔案test.i(可以開啟後與預先處理前進行比對,當然長度會嚇你一跳)    
       作用:  讀取c來源程式,對偽指令和特殊符號進行處理。包括宏,條件編譯,包含的標頭檔,以及一些特殊符號。基本上是一個replace的過程。

第二步 編譯及最佳化
        命令:  gcc -o test.s -S test.i
             或者 /路徑/cc1 -o test.s test.i
        結果: 產生彙編檔案test.s(可開啟後查看源檔案產生的彙編碼)
        作用: 通過詞法和文法分析,確認所有指令符合文法規則(否則報編譯錯),之後翻譯成對應的中間碼,在linux中被稱為RTL(Register Transfer Language),通常是平台無關的,這個過程也被稱為編譯前端。編譯後端對RTL樹進行裁減,最佳化,得到在目標機上可執行檔彙編代碼。gcc採用as 作為其彙編器,所以彙編碼是AT&T格式的,而不是Intel格式,所以在用gcc編譯嵌入式彙編時,也要採用AT&T格式。
       
第三步 彙編
        命令: gcc -o test.o -c test.s
               或者 as -o test.o test.s
        結果:   產生目標機器指令檔案test.o(可用objdump查看)
        作用:  把組合語言代碼翻譯成目標機器指令, 用file test.o 可以看到test.o是一個relocatable的ELF檔案,通常包含.text .rodata程式碼片段和資料區段。可用readelf -r test.o查看需要relocation的部分。
       
第四步 連結
        命令: gcc -o test test.o
               或者 ld -o test test.o
        結果:   產生可執行檔test (可用objdump查看)
        作用:  將在一個檔案中引用的符號同在另外一個檔案中該符號的定義連結起來,使得所有的這些目標檔案連結成為一個能被作業系統載入到記憶體的執行體。(如果有不到的符號定義,或者重複定義等,會報連結錯)。用file test 可以看到test是一個executable的ELF檔案。
       
        當然連結的時候還會用到靜態連結庫,和動態串連庫。靜態庫和動態庫都是.o目標檔案的集合。
        靜態庫:
        命令:ar -v -q test.a test.o
        結果: 產生靜態連結庫test.a
        作用: 靜態庫是在連結過程中將相關代碼提取出來加入可執行檔的庫(即在連結的時候將函數的代碼將從其所在地靜態連結庫中被拷貝到最終的可執行程式中),ar只是將一些別的檔案集合到一個檔案中。可以打包,當然也可以解包。
       
        動態庫: 
        命令:  gcc -shared test.so test.o
             或者/PATH/collect2 -shared test.so test.o (省略若干參數)
        結果:  產生動態串連庫test.so
        作用: 動態庫在連結時只建立一些符號表,而在啟動並執行時候才將有關庫的代碼裝入記憶體,映射到運行時相應進程的虛地址空間。如果出錯,如找不到對應的.so檔案,會在執行的時候報動態串連錯(可用LD_LIBRARY_PATH指定路徑)。用file test.so可以看到test.so是shared object的ELF檔案。
       
當然以上各步可以一步或若干步一起完成,如gcc -o test test.c直接得到可執行檔。

附:
    ELF檔案格式
    ELF檔案格式是ABI(Application Binary Interface)的一部分,被Tool Interface Standards committee作為在32位Intel架構下可移植的目標檔案格式。其格式比較複雜,這裡就不細講了,只說說其類型。
    在specification 1.1中定義了的類型。表示在ELF header中的e_type
    Name        Value  Meaning
    ====        =====  =======
    ET_NONE         0  No file type
    ET_REL          1  Relocatable file
    ET_EXEC         2  Executable file
    ET_DYN          3  Shared object file
    ET_CORE         4  Core file
    ET_LOPROC  0xff00  Processor-specific
    ET_HIPROC  0xffff  Processor-specific
   
    主要的有4種
    1. Relocatable file 保留了代碼和資料,被用來和其他的object file一起建立可執行檔檔案或者是shared object file. (也就是我們常見的.o檔案)
    2. Executable file 保留了用來執行的程式,該檔案可以被系統exec()載入用以建立程式進程。(也就是我們常說的可執行檔)
    3. Shared object file 保留了代碼和資料,以在兩種情況下被串連,一是link editor如ld,可以用它與其他的Relocateble或者Shared的object file一起建立另一個object file. 二是與Executable file或者其他的Shared object file動態連結成為一個進程映像。(也就是我們常說的動態連結程式庫,或者.so檔案)   
    4. Core file 的內容在規範中沒有指明,目前多用來記錄core dump資訊。

=============================================================================

本文對gcc 編譯器如何工作做一個概要描述.   更為詳細的資訊請參考編譯器手冊。       當我們進行編譯的時候,要使用一系列的工具,我們稱之為工具鏈.其中包括:前置處理器CPP,編譯器前端gcc/g++,彙編器as,連接器ld. 一個編譯過程包括下面幾個階段: (1)預先處理.前置處理器CPP將對源檔案中的宏進行展開。 (2)編譯.gcc將c檔案編譯成彙編檔案。  (3)彙編。as將彙編檔案編譯成機器碼。  (4)串連。ld將目標檔案和外部符號進行串連,得到一個可執行二進位檔案。    下面以一個很簡單的test.c來探討這個過程。  #define NUMBER  (1+2) int main() {         int x=NUMBER;          return 0;  }  (1)預先處理:gcc會首先調用CPP進行預先處理: CPP test.c >test.i 預先處理的輸出為檔案test.i。 我們用cat test.i查看test.i的內容如下: int main() {    int x=(1+2);       return 0;  }  我們可以看到,檔案中宏定義NUMBER出現的位置被(1+2)替換掉了,其它的內容保持不變。  (2)gcc將c檔案編譯成彙編檔案。 接下來gcc會執行gcc -S test.i得到的輸出檔案為test.s .   (3)as將彙編檔案編譯成機器碼。 as test.s -o test.o得到輸出檔案為test.o.  test.o中為目標機器上的二進位檔案. 用nm查看檔案中的符號: nm test.o輸出如下:    00000000 b .bss   00000000 d .data      00000000 t .text    U ___main      U __alloca   00000000 T _main  既然已經是二進位目標檔案了,能不能執行呢?試一下./test.o,提示cannot execute binary file.原來___main前面的U表示這個符號的地址還沒有定下來,T表示這個符號屬於程式碼片段。ld串連的時候會為這些帶U的符號確定地址。   (4)串連。 串連需要指定庫的位置。通常程式中會有很多的外部符號,因此需要指定的位置就會很多。不過,我們之需要調用gcc即可,ld會自己去找這些庫的位置。gcc test.o>test就得到了最終的可執行程式了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.