【Code_Base】編譯原理的簡(jiǎn)述

概述

C和C++編譯器是集成的,編譯一般分為如下四個(gè)步驟:
a. 預(yù)處理(preprocessing) ------------ cpp/gcc -E
b. 編譯(compilation) ------------------ cc1 / gcc -S
c. 匯編(assembly) --------------------- as
d. 鏈接(linking) ------------------------ ld

下面就以一個(gè)經(jīng)典的hello程序?yàn)槔私庖幌律鲜龅乃牟?/h3>
#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

1. 預(yù)處理階段:預(yù)處理器(cpp)根據(jù)字符#開(kāi)頭的命令,修改原始的C程序。例如,hello.c中第一行的#include <stdio.h>命令告訴預(yù)處理器讀取系統(tǒng)頭文件stdio.h的內(nèi)容,并把它直接插入到程序中。結(jié)果得到另一個(gè)C程序,通常以.i作為文件擴(kuò)展名。

2. 編譯階段:編譯器(ccl)將文本文件hello.i翻譯成文件本文件hello.s,它包含一個(gè)匯編語(yǔ)言程序。該程序包含函數(shù)main的定義,如下所示:

1   main:
2       subq     $8, %rsp
3       movl     $.LCO, %edi
4       call     puts
5       movl     $0, %eax
6       addq     $8, %rsp
7       ret
定義中2~7行的的每條語(yǔ)句都以一種文本格式描述了一條低級(jí)機(jī)器語(yǔ)言指令。匯編語(yǔ)言是非常有用的,因?yàn)樗鼮椴煌呒?jí)語(yǔ)言的不同編譯器提供了通用的輸出語(yǔ)言。例如,C編譯器和Frotran編譯器產(chǎn)出的輸出文件用的都是一樣的匯編語(yǔ)言

3. 匯編階段:接下來(lái),匯編器(as)將hello.s翻譯成機(jī)器語(yǔ)言指令,并把這些指令打包成一種叫做可重定位目標(biāo)程序的格式,并將結(jié)果保存到目標(biāo)文件hello.o中,hello.o是一個(gè)二進(jìn)制文件,它包含的17個(gè)字節(jié)是函數(shù)main的指令編碼。如果我們?cè)谖谋揪庉嬈骼锩娲蜷_(kāi)hello.o文件,看到的將是一堆亂碼。

4. 鏈接階段:hello程序調(diào)用了printf函數(shù),他是每個(gè)C編譯器都提供的標(biāo)準(zhǔn)C庫(kù)的一個(gè)函數(shù)。printf函數(shù)存在于一個(gè)名為printf.o的單獨(dú)的預(yù)編譯好了的目標(biāo)文件中,而這個(gè)文件必須以某種方式合并到我們的hello.o程序中,鏈接器(ld)就負(fù)責(zé)處理這種合并。結(jié)果就得到hello文件,他是一個(gè)可執(zhí)行目標(biāo)文件或簡(jiǎn)稱為可執(zhí)行文件,可以被加載到內(nèi)存中,有系統(tǒng)執(zhí)行。

  • 為了更好的理解可以參考下圖:


函數(shù)庫(kù)

  • 函數(shù)庫(kù)一般分為靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)兩種
  1. 靜態(tài)庫(kù)是指編譯鏈接時(shí),把庫(kù)文件的代碼全部加入到可執(zhí)行文件中,因此生成的文件比較大,但在運(yùn)行時(shí)也就不再需要庫(kù)文件了。其后綴名一般為”.a“。
  2. 動(dòng)態(tài)庫(kù)與之相反,在編譯鏈接時(shí)并沒(méi)有把庫(kù)文件的代碼加入到可執(zhí)行文件中,而是在程序執(zhí)行時(shí)由運(yùn)行時(shí)鏈接文件加載庫(kù),這樣可以節(jié)省系統(tǒng)的開(kāi)銷。動(dòng)態(tài)庫(kù)一般后綴名為”.so”,如前面所述的libc.so.6就是動(dòng)態(tài)庫(kù)。Gcc在編譯時(shí)默認(rèn)使用動(dòng)態(tài)庫(kù)。
靜態(tài)庫(kù)生成方法:  
    ar cr libxxx.a file1.o file2.o  
    就是把file1.o和file2.o打包生成libxxx.a靜態(tài)庫(kù)  
使用方法
    gcc test.c -L/path -lxxx -o test  


動(dòng)態(tài)庫(kù)生成方法:
    gcc -fPIC -shared file1.c -o libxxx.so  
也可以分成兩部來(lái)寫(xiě)  
    //這一步生成file1.o 
    gcc -fPIC file1.c -c  
    gcc -shared file1.o -o libtest.so  
使用方法
    gcc test.c -L/path -lxxx -o test  
  • 靜態(tài)庫(kù)鏈接時(shí)搜索路徑順序:
  1. ld會(huì)去找GCC命令中的參數(shù)-L
  2. 再找gcc的環(huán)境變量LIBRARY_PATH
  3. 再找內(nèi)定目錄 /lib /usr/lib /usr/local/lib 這是當(dāng)初compile gcc時(shí)寫(xiě)在程序內(nèi)的
  • 動(dòng)態(tài)鏈接時(shí)、執(zhí)行時(shí)搜索路徑順序
  1. 編譯目標(biāo)代碼時(shí)指定的動(dòng)態(tài)庫(kù)搜索路徑
  2. 環(huán)境變量LD_LIBRARY_PATH指定的動(dòng)態(tài)庫(kù)搜索路徑
  3. 配置文件/etc/ld.so.conf中指定的動(dòng)態(tài)庫(kù)搜索路徑
  4. 默認(rèn)的動(dòng)態(tài)庫(kù)搜索路徑/lib
  5. 默認(rèn)的動(dòng)態(tài)庫(kù)搜索路徑/usr/lib

環(huán)境變量

  • LIBRARY_PATH環(huán)境變量:指定程序靜態(tài)鏈接庫(kù)文件搜索路徑
  • LD_LIBRARY_PATH環(huán)境變量:指定程序動(dòng)態(tài)鏈接庫(kù)文件搜索路徑


聲明:本文參考自《深入理解計(jì)算機(jī)系統(tǒng)》


GitHub主頁(yè)

CSDN Blog

Email:jinjob@icloud.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容