編譯鏈結簡介

2021-10-10 23:53:18 字數 2474 閱讀 1724

我們都知道,機器上執行的程式都是二進位制程式,但是我們編寫的c語言**卻是由乙個個字元加上某些規則「裝配」而成的文字檔案,這些文字檔案是怎麼樣轉換為二進位制程式的呢?這裡面可有大奧秘!從c原始碼檔案到二進位制檔案,大概經歷了以下幾個過程:

下面通過乙個例子來分析,這是寫好的三個原始碼檔案,三個原始碼檔案均放在用乙個目錄下:

// mainfunc.c

# include

"twonumsum.h"

intmain()

// twonumsum.h

# ifndef two_num_sum_h

# define two_num_sum_h

intaddtwonum

(int

,int);

// function declaration

# endif

// twonumsum.c

# include

"twonumsum.h"

intaddtwonum

(int x,

int y)

如果直接在命令列中輸入:

$ gcc mainfunc.c twonumsum.c -o a.out
則資料夾下會多出乙個a.out檔案,該檔案就是經過gcc編譯得到的在linux上二進位制可執行檔案。事實上,該過程在背後其實執行了四個步驟,分別是預處理、編譯、彙編和鏈結,而gcc命令也只是這些步驟對應的後台程式的包裝。那麼具體這四個階段發生了什麼呢,我們一一來看。

首先在預處理階段,可以通過以下命令來讓gcc呼叫預處理器(cpp),生成預處理後的.i檔案:

$ gcc -e mainfunc.c -o mainfunc.i

$ gcc -e twonumsum.c -o twonumsum.i

生成的.i檔案如下圖:

其實,預處理過程主要是處理源**檔案中的以 「#」開始的預編譯指令,主要處理規則如下:

編譯過程就是編譯程式(ccl)把預處理完的檔案經過一系列分析生成相應的.s彙編**檔案。對應命令如下:

gcc -s mainfunc.i -o mainfunc.s

gcc -s twonumsum.i -o twonumsum.s

生成的.s檔案如下圖:

當然,編譯過程的細枝末節也是一門大學問了!

對於上述生成的.s檔案中的彙編**,機器自然是無法執行的,那彙編階段就是彙編器(as)將上述的彙編**彙編成機器可以執行的二進位制**,生成.o目標檔案。彙編的過程是很簡單的,沒有複雜的語法,只需要根據彙編指令和機器指令的對照表一一翻譯就可以了。對應命令如下:

$ gcc -c mainfunc.s -o mainfunc.o

$ gcc -c twonumsum.s -o twonumsum.o

此時生成.o就不能用編輯器開啟檢視內容了,但是我們可以鍵入ubuntu下的file命令來看看該檔案的基本屬性:

發現生成的.o檔案是elf可重定位檔案,elf其實就是linux作業系統下的一種檔案的格式,主要有可重定位檔案,可執行檔案和共享檔案。

回想剛剛的main函式,其中呼叫了twonumsum這個函式,哎不對,經過預處理後,明明main函式檔案內也僅僅包括了twonumsum函式的宣告,並沒有它的實現,那main函式是怎麼實現呼叫的呢,其實這裡就是鏈結器(ld)發揮作用的時候了。 鏈結器就是負責把各個模組之間相互引用的部分處理好,使得各個模組之間可以正確地銜接,然後生成可執行二進位制程式。對應命令如下:

$ gcc mainfunc.o twonumsum.o -o a.out
這樣就生成了可執行檔案a.out,如果輸入./a.out會發現shell沒有任何反饋,但是a.out一定是在機器內執行了哦,只是我們讓他產生輸入輸出結果而已啦!況且,根據linux哲學,沒有反饋就是最好的反饋嘛。

可以看到,兩個源**檔案mainfunc.c和twonumsum.c從預處理到編譯到彙編都是單獨進行的,直到鏈結的時候才會拼接到了一起生成最終的可執行檔案a.out。到這裡,應該對編譯鏈結幹了啥有個初步的了解了,編譯鏈結本身是乙個龐大的知識體系,如果對其有興趣,可以查閱相關資料自行學習。

C語言編譯和鏈結過程簡介

一 編譯過程簡介 編譯過程可以分為4部分內容組成 預處理器 編譯器 彙編器 鏈結器 1 預處理器 1 處理所有的注釋,以空格代替 2 講所有的 define刪除,並且展開所有的巨集定義 3 處理條件編譯指令 if,ifdef elif,else endif 4 處理 include,展開檔案包含 5...

編譯鏈結詳解

因為這相當於在標頭檔案裡定義了const物件。作為例外,int char等可以進行就地初始化,是因為這些變數可以直接被優化為立即數,就和巨集一樣。此外,對於類的const 非static 成員變數,只能在建構函式的初始化列表中初始化,不能在類內部直接賦值,也不能在類外部賦值。而對於static co...

編譯和鏈結

一般來說,無論是c c 首先要把原始檔編譯成中間 檔案,在windows下也就是 obj 檔案,unix下是 o 檔案,即 object file,這個動作叫做編譯 compile 然後再把大量的object file合成執行檔案,這個動作叫作鏈結 link 編譯時,編譯器需要的是語法的正確,函式與...