gcc 編譯過程

現代編譯器常見的編譯過程:
源文件-->預處理-->編譯/優化-->彙編-->鏈接-->可執行文件

對於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信息。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章