天天看點

看完這篇文章之後,終于明白了編譯到底怎麼回事。

看完這篇文章之後,終于明白了編譯到底怎麼回事。

1

對于同一個語句,有如下三種:進階語言、低級語言、機器語言的表示

C語言 

a=b+1;

彙編語言 

mov -0xc(%ebp),%eax

add $0x1,%eax

mov %eax,-0x8(%ebp)

機器語言 

8b 45 f4

83 c0 01

89 45 f8

我們都知道,機器是隻能做數字計算的,能夠讓機器去運算的、數字的語言就是機器語言,除此之外的所有計算機語言都是非機器語言。這樣的相對于機器語言的進階語言都需要一個轉換,從進階、機器不可了解,轉換為機器可了解的機器語言。這樣的一個轉換過程就叫做<code>編譯(Compile)</code>,<code>由編譯器(Compiler)</code>來完成。

由C轉換為彙編語言這一過程是由<code>彙編器(Assembler)</code>來執行的。

C和彙編語言轉換為機器語言都是由編譯器來完成的。

2

這裡面,C是可跨平台的,也可以說是與平台無關的。這裡的平台有兩種說法,一種是指計算機的<code>體系(Architecture)</code>,另一種是指<code>作業系統(Operate System)</code>,也可以是指兩種的結合。不同的平台,他們所需要的執行機器語言的指令集是不同的。C的跨平台性是指,隻需要編寫一份不需要修改的C程式代碼,就可以在不同體系、不同作業系統的計算機上運作。這都要靠編譯器的功勞,編譯器将C程式翻譯為了适合目前計算機體系的機器語言。

下面說一下将C語言編譯為機器語言的整個過程:

首先,我們寫出一份C程式代碼,命名該代碼為<code>hello.c</code>,這個代碼檔案,我們稱之為<code>源代碼(Srouce Code)</code>。

然後我們運作編譯器,對該源代碼檔案進行編譯,在整個編譯的過程中,編譯器并不會執行該源代碼,隻是生成一份新的機器語言代碼檔案,如<code>hello.out</code>。這份新生成的代碼檔案稱為<code>目标代碼(Object Code)</code>或<code>可執行代碼(Executable)</code>。

3

對于編譯過程,裡面還涉及到具體的一些可以說的細節步驟。

在<code>Linux</code>下,使用<code>gcc</code>編譯器:

預編譯hello.c檔案:

執行成功後就會生成一個新的<code>hello.i</code>的檔案,可以用編輯器(Vim)檢視它的内容,這個檔案就是經過<code>預編譯</code>後的内容。

<code>預編譯</code>又稱為預處理,是做些代碼文本的替換工作。預編譯可以處理<code>#</code>開頭的指令,比如拷貝<code>#include</code>包含的檔案代碼,<code>#define</code>的宏定義的替換,條件編譯等。

純粹的進行編譯:

把.i檔案寫為hello.c也行,就是跳過手動預編譯,直接完成預編譯和編譯兩個過程。這時會得到一個hello.s檔案,打開看一下,裡面是編譯好的使用于目前體系結構的彙編代碼。

把彙編代碼進行彙編可執行:

把.s檔案換成.c也行,就是自動完成預編譯、編譯和彙編三個過程。現在得到一個hello.o檔案,這是一個二進制檔案,但不是最後的可執行二進制檔案,因為它還缺少最後一步連接配接處理。

最後對.o檔案進行連接配接,我們這裡就一個.o檔案是以簡單,經常是需要有多個.o檔案需要連接配接。連接配接執行:

如果把最後的.o檔案寫成.c,那就和最開始我們用hello.c編譯時示範的那樣了。實際上那樣是完成了預編譯、編譯、彙編和連接配接一連串的過程。

想了解更多gcc的隻是可以到GNU的網站上去看看。

BTW,gdb是常用的調式軟體。

繼續閱讀