什么叫編譯?


經常看到文件編譯,編譯到底是干嘛?

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

因為機器是只能做數字計算的,能夠讓機器去運算的,數字的語言就是機器語言。除此之外的所有計算機語言都是非機器語言。為了讓機器可理解,相對於機器語言的高級語言都需要一個轉換,從高級、機器不可理解,轉換為機器可理解的機器語言,這樣的一個轉換過程就叫做 編譯(Compile),由 編譯器(Compiler)來完成。

由 C 轉換為 匯編語言 這一過程是由 匯編器(Assembler)來執行的。

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

 

2、將C語言編譯為機器語言的整個過程

 

 

在Linux下,使用gcc編譯器:

1、預編譯hello.c文件:

gcc -E -o hello.i hello.c

執行成功后,會生成一個新的hello.i 的文件,可以用編輯器(Vim)查看它的內容,這個文件就是經過預編譯后的內容。

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

預處理的過程主要處理包括以下過程:

將所有的#define刪除,並且展開所有的宏定義;

處理所有的條件預編譯指令,比如 #if  #ifdef  #elif  #else  #endif等;

處理#include預編譯指令,將被包含的文件插入到該預編譯指令的位置;

刪除所有注釋 "//" 和 "/**/";

添加行號和文件標識,以便編譯時產生調試用的行號及編譯錯誤警告行號;

保留所有的#pragma編譯器指令,因為編譯器需要使用它們;

 

通常使用以下命令來處理預處理:

gcc -E hello.c -o hello.i

  參數-E表示只進行預處理,或者也可以使用以下指令完成預處理過程:

cpp hello.c > hello.i  /* cpp - The C Preprocessor*/

  直接cat hello.i 你就可以看到預處理后的代碼。

 

2、純粹的進行編譯:

gcc -S -o hello.s hello.i

把.i文件寫為hello.c也行,就是跳過手動預編譯,直接完成預編譯和編譯兩個過程。這時會得到一個hello.s文件,打開看一下,里面是編譯好的適用於當前體系結構的匯編代碼。

編譯過程就是把預處理完的文件進行一系列的詞法分析、語法分析、語義分析及優化后生成相應的匯編代碼。

gcc -S hello.i -o hello.s

  或者:

/usr/lib/gcc/i486-linux-gnu/4.4/cc1 hello.c

  注:現在版本的gcc把預處理和編譯兩個步驟合成一個步驟,用cc1工具來完成。gcc其實是后台程序的一些包裝,根據不同參數去調用其他的實際處理程序,比如:預編譯編譯程序cc1、匯編器as、連接器ld。可以看到編譯后的匯編代碼(hello.s)如下:

  .file   "hello.c"
    .section    .rodata
.LC0:
    .string "Hello, world."
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, (%esp)
    call    puts
    movl    $0, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

  

3、把匯編代碼進行匯編可執行:

gcc -c -o hello.o hello.s

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

匯編器是將匯編代碼轉變成機器可以執行的命令,每一個匯編語句幾乎都對應一條機器指令。匯編相對於編譯過程比較簡單,根據匯編指令和機器指令的對照表一一翻譯即可。

gcc -c hello.c -o hello.o

或者:

as hello.s -o hello.co

  由於hello.o的內容為機器碼,不能以普通文本形式查看(vi打開看到的是亂碼)。

 

4、鏈接

最后對.o文件進行鏈接,這里就一個.o文件所以簡單,經常是需要有多個.o文件需要鏈接。鏈接執行:

gcc -o hello hello.o

如果把最后的.o文件寫成.c,那就和最開始我們用hello.c編譯時示范的那樣了。實際上那樣是完成了預編譯、編譯、匯編和鏈接一連串的過程。

通過調用鏈接器ld來鏈接程序運行需要的一大堆目標文件,以及所依賴的其它庫文件,最后生成可執行文件。

ld -static crt1.o crti.o crtbeginT.o hello.o -start-group -lgcc -lgcc_eh -lc-end-group crtend.o crtn.o (省略了文件的路徑名)

  


免責聲明!

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



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