接觸程式設計還在麼長時間,還沒有好好理解下一段**從.c到可執行程式的過程。
先看一下gcc的常用引數:
[引數詳解]
-c 只啟用預處理,編譯,和彙編,也就是他只把程式做成obj檔案
例子用法:
gcc
-c hello.c
他將生成.o的obj檔案
-s 只啟用預處理和編譯,就是指把檔案編譯成為彙編**。
例子用法
gcc
-s hello.c
他將生成.s的彙編**,你可以用文字編輯器察看
-e 只啟用預處理,這個不生成檔案,你需要把它重定向到乙個輸出檔案裡
面. 例子用法:
gcc
-e hello.c
>
pianoapan.txt
gcc
-e hello.c
| more
慢慢看吧,乙個hello
word
也要與處理成800行的**
-o 制定目標名稱,預設的時候,gcc
編譯出來的檔案是a.out,可以用-o指定生成的檔案的名稱
例子用法
gcc
-o hello.exe
hello.c
(哦,windows用習慣了)
gcc
-o hello.asm
-s hello.c
-g 只是編譯器,在編譯的時候,產生除錯資訊。使用objdump -ds hello《可執行檔案》 可以得到反彙編**,其中會帶有對應行c**
現在來簡單總結一下。以簡單的hello world為例。
#include #define num 10
/* hello world */
int main(int argc, char* argv)
通常我們使用gcc來生成可執行程式,命令為:gcc hello.c,預設生成可執行檔案a.out
其實編譯(包括鏈結)的命令:gcc hello.c 可分解為如下4個大的步驟:
再來一張圖:
1. 預處理(preproceessing)
預處理的過程主要處理包括以下過程:
通常使用以下命令來進行預處理:
gcc -e hello.c -o hello.i
引數-e表示只進行預處理 , -o 是引數,後面需要跟輸出的檔名,如果不跟,那麼預處理後的**就會列印在終端上,-o就表示輸出到某個檔案中,類似於重定向。
或者也可以使用以下指令完成預處理過程
cpp hello.c > hello.i /* cpp – the c preprocessor */
直接cat hello.i 你就可以看到預處理後的**
2. 編譯(compilation)
編譯過程就是把預處理完的檔案進行一系列的詞法分析,語法分析,語義分析及優化後生成相應的彙編**。
$gcc –s hello.i –o hello.s
或者$ /usr/lib/gcc/i486-linux-gnu/4.4/cc1 hello.c
注:現在版本的gcc把預處理和編譯兩個步驟合成乙個步驟,用cc1工具來完成。gcc其實是後台程式的一些包裝,根據不同引數去呼叫其他的實際處理程式,比如:預編譯編譯程式cc1、彙編器as、聯結器ld
3. 彙編(assembly)
彙編器是將彙編**轉變成機器可以執行的命令,每乙個彙編語句幾乎都對應一條機器指令。彙編相對於編譯過程比較簡單,根據彙編指令和機器指令的對照表一一翻譯即可。
$ gcc –c hello.c –o hello.o
或者$ as hello.s –o hello.co
由於hello.o的內容為機器碼,不能以普通文字形式的檢視(vi 開啟看到的是亂碼)。
gcc hello.c -o hello.o??? 是什麼情況呢? 檔案大小和上面的不一樣
4. 鏈結(linking)
通過呼叫鏈結器ld來鏈結程式執行需要的一大堆目標檔案,以及所依賴的其它庫檔案,最後生成可執行檔案。
ld -static crt1.o crti.o crtbegint.o hello.o -start-group -lgcc -lgcc_eh -lc-end-group crtend.o crtn.o (省略了檔案的路徑名)。
-static表示靜態鏈結
helloworld的大體編譯和鏈結過程就是這樣了,那麼編譯器和鏈結器到底做了什麼呢?
編譯過程可分為6步:掃瞄(詞法分析)、語法分析、語義分析、源**優化、**生成、目標**優化。
詞法分析:掃瞄器(scanner)將源代的字串行分割成一系列的記號(token)。lex工具可實現詞法掃瞄。
語法分析:語法分析器將記號(token)產生語法樹(syntax tree)。yacc工具可實現語法分析(yacc: yet another compiler compiler)。
語義分析:靜態語義(在編譯器可以確定的語義)、動態語義(只能在執行期才能確定的語義)。
源**優化:源**優化器(source code optimizer),將整個語法書轉化為中間**(intermediate code)(中間**是與目標機器和執行環境無關的)。中間**使得編譯器被分為前端和後端。編譯器前端負責產生機器無關的中間**;編譯器後端將中間**轉化為目標機器**。
目標**生成:**生成器(code generator).
目標**優化:目標**優化器(target code optimizer)。
鏈結的主要內容是把各個模組之間相互引用的部分處理好,使得各個模組之間能夠正確地銜接。
鏈結的主要過程包括:位址和空間分配(address and storage allocation),符號決議(symbol resolution),重定位(relocation)等。
鏈結分為靜態鏈結和動態鏈結。
靜態鏈結是指在編譯階段直接把靜態庫加入到可執行檔案中去,這樣可執行檔案會比較大。
而動態鏈結則是指鏈結階段僅僅只加入一些描述資訊,而程式執行時再從系統中把相應動態庫載入到記憶體中去。
靜態鏈結的大致過程如下圖所示:
static linking
C程式編譯過程
題記 前幾天去華為面試實習生,面試官問了個問題,讓我說出乙個程式的詳細編譯過程,當時磕磕絆絆說了一堆東西,事後自己都不知道當時說了什麼,慚愧。c語言編譯過程 編譯,編譯程式讀取源程式 字元流 對之進行詞法和語法的分析,將高階語言指令轉換為功能等效的彙編 再由匯程式設計序轉換為機器語言,並且按照作業系...
C 程式編譯過程
首先是編譯過程整體簡介 編譯過程主要分為 4個過程 1 編譯預處理 預編譯程式完成的工作,可以說成是對源程式的 替換 工作。經過這個過程,生成乙個沒有巨集定義 沒有條件編譯指令 沒有特殊符號的輸出檔案。2 編譯 優化階段 通過詞法分析 語法分析,在確認所有的指令都符合語法規則之後,將其翻譯成等價的中...
C程式編譯過程
gcc編譯c 會有四個階段 預處理 將c 中的標頭檔案和巨集進行處理 彙編 把彙編 轉化成機器指令,並以特定的二進位制格式輸出儲存在 o這樣的目標檔案中 流程圖 參考閱讀 3.c程式分析 gcc e hello.c o hello.i 預處理 gcc s hello.i o hello.s 編譯 g...