gcc編譯鏈接原理及使用


1、gcc 和 arm-linux-gcc的常用選項

 

gcc 的使用方法:

gcc    【選項】    文件名

 

gcc常用選項:

  -v:查看gcc 編譯器的版本,顯示gcc執行時的詳細過程

  -o    < file >             Place  the output  into   < file > 

          指定輸出文件名為file,這個名稱不能跟源文件名同名  

  -E        Preprocess only; do not compile, assemble or link

           只預處理,不會編譯、匯編、鏈接

  -S        Compile only; do not assemble or link

          只編譯,不會匯編、鏈接

  -c        Compile and assemble, but do not link

           

       

//=======================================

gcc  -v: 查看 gcc 編譯器的版本

 

方式1:

gcc  hello.c      輸出一個 a.out,然后 ./a.out 來執行該應用程序

 

gcc   -o   hello   hello.c     輸出hello ,然后 ./hello 來執行該應用程序。

 

方式2:

gcc  -E   -o  hello.i    hello.c

gcc  -S   -o  hello.s    hello.i

gcc  -c   -o  hello.o   hello.s

gcc   -o   hello    hello.o

 

 

.o: object   file (OBJ文件)

小結:

1)輸入文件的后綴名和選項共同決定gcc到底執行哪些操作。

 

 

2)在編譯過程中,除非使用了-E、-S、-C選項(或者編譯出錯阻止了完整的編譯過程)

  否則最后的步驟都是鏈接。

 

方式3:

gcc  -c   -o  hello.o   hello.s

gcc   -o   hello    hello.o

 

gcc會對.c文件默認進行預處理操作, -c再來指明了編譯、匯編,從而得到.o文件

再通過gcc  -o  hello   hello.o   將.o文件進行鏈接,得到可執行應用程序。

 

 鏈接就是將匯編生成的OBJ文件、系統庫的OBJ文件、庫文件鏈接起來,

最終生成可以在特定平台運行的可執行程序。

 

crt1.o、crti.o、crtbegin.o、crtend.o、crtn.o是gcc加入的系統標准啟動文件,

對於一般應用程序,這些啟動是必需的。

 

-lc:鏈接libc庫文件,其中libc庫文件中就實現了printf等函數。

 

gcc  -v  -nostdlib  -o   hello  hello.o 會提示因為沒有鏈接系統標准啟動文件和標准庫文件,而鏈接失敗。

這個-nostdlib選項常用於裸機 /bootloader 、linux 內核等程序,因為它們不需要啟動文件、標准庫文件。

 

一般應用程序才需要系統標准啟動文件和標准庫文件。、

裸機 /BootLoader、linux內核燈程序不需要啟動文件、標准庫文件。

 

動態鏈接使用動態鏈接庫進行鏈接,生成的程序在執行的時候需要加載所需的動態庫才能巡行。

動態鏈接生成的程序體積較小,但是必須依賴所需的動態庫,否則無法執行。

 

靜態鏈接使用靜態庫進行鏈接,生成的程序包含程序運行所需要的全部庫,可以直接運行,

不過靜態鏈接生成的程序比較大。

 

gcc  -c  -o  hello.o  hello.c

gcc   -o  hello_shared  hello.o

gcc   -static  -o  hello_static  hello.o

 

2、舉例說明編譯鏈接過程

 一個C/C++文件要經過預處理(preprocessing)、編譯(compilation)、匯編(assembly)、和連接(linking)才能變成可執行文件。

以下列程序為例,追層來分析編譯過程。 
hello.c:

#include <stdio.h> #define MAX 20 #define MIN 10 #define _DEBUG #define SetBit(x) (1<<x) int main(int argc, char* argv[]) { printf("Hello World \n"); printf("MAX = %d,MIN = %d,MAX + MIN = %d\n",MAX,MIN,MAX + MIN); #ifdef _DEBUG printf("SetBit(5) = %d,SetBit(6) = %d\n",SetBit(5),SetBit(6)); printf("SetBit( SetBit(2) ) = %d\n",SetBit( SetBit(2) )); #endif return 0; }

 

① 預處理:

gcc -E -o hello.i hello.c

這里寫圖片描述

  • 預處理就是將要包含(include)的文件插入原文件中、將宏定義展開、根據條件編譯命令選擇要使用的代碼,最后將這些代碼輸出到一個“.i”文件中等待進一步處理。 

② 編譯:

gcc -S -o hello.s hello.i

這里寫圖片描述

  • 編譯就是把C/C++代碼(比如上面的”.i”文件)“翻譯”成匯編代碼。

③ 匯編:

gcc -c -o hello.o hello.s

這里寫圖片描述

.o:object file(OBJ文件) 這里表現為二進制目標文件: 
這里寫圖片描述

  • 匯編就是將第二步輸出的匯編代碼翻譯成符合一定格式的機器代碼,在Linux系統上一般表現位ELF目標文件(OBJ文件)。

④ 鏈接:

gcc -o hello hello.o

這里寫圖片描述

  • 鏈接就是將匯編生成的OBJ文件、系統庫的OBJ文件、庫文件鏈接起來,最終生成可以在特定平台運行的可執行程序。 

總結:在編譯過程中。除非使用了”-c”,“-S”,或”-E”選項(或者編譯錯誤阻止了完整的過程),否則統一完整鏈接步驟。

譬如:gcc hello.c 和gcc -o hello hello.c都已經完成鏈接操作。 
這里寫圖片描述

又如:gcc -c -o hello.o hello.c 
這里寫圖片描述

鏈接原理:

gcc -c -o hello.o hello.c 不作最后一步鏈接,得到hello.o二進制OBJ文件

gcc -v -o hello hello.o 我們來看一樣鏈接過程是怎樣的:


  • crt1.o、crti.o、crtbegin.o、crtend.o、crtn.o是gcc加入的系統標准啟動文件,對於一般應用程序,這些啟動是必需的。
  • -lc:鏈接libc庫文件,其中libc庫文件中就實現了printf等函數。

① 動態鏈接:動態鏈接使用動態鏈接庫進行鏈接,生成的程序在執行的時候需要加載所需的動態庫才能運行。  動態鏈接生成的程序體積較小,但是必須依賴所需的動態庫,否則無法執行。

默認使用動態鏈接:gcc -o hello_shared hello.o

這里寫圖片描述

② 靜態鏈接:靜態鏈接使用靜態庫進行鏈接,生成的程序包含程序運行所需要的全部庫,可以直接運行,不過靜態鏈接生成的程序體積較大。

gcc -static -o hello_static hello.o

這里寫圖片描述

③ -nostartfiles

不鏈接系統標准啟動文件,而標准庫文件仍然正常使用: 
gcc -v -nostartfiles -o hello hello.o

這里寫圖片描述


④ -nostdlib(最常用)

不鏈接系統標准啟動文件和標准庫文件: 
gcc -v -nostdlib -o hello hello.o

這里寫圖片描述
- 會提示因為沒有鏈接系統標准啟動文件和標准庫文件,而鏈接失敗。 
- 這個-nostdlib選項常用於裸機/bootloader、linux內核等程序,因為它們不需要啟動文件、標准庫文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM