程序員的自我修養(yǎng)

編譯和連接

1. 預(yù)處理(Prepressing)

  • 將所有的#define刪除,并展開宏定義。
  • 處理所有的條件預(yù)編譯,比如#if #ifdef #elif #else #endif
  • 處理#include預(yù)編譯指令,將包含的文件插入到該預(yù)編譯指令的位置,注意,這個過程是遞歸。
  • 刪除所有的///* */
  • 添加行號和文件名標(biāo)識
  • 保留所有的#pragma 編譯指令

2. 編譯(Compilation)

編譯就是把預(yù)處理完的文件進(jìn)行一系列的詞法分析、語法分析、語義分析及優(yōu)化后生產(chǎn)相應(yīng)的匯編代碼文件。

gcc 這個命令只是后臺程序的包裝,它會根據(jù)不同的參數(shù)要求去調(diào)用預(yù)編譯編譯程序cc1、匯編器as、鏈接器來ld。

3. 匯編(Assembly)

將匯編代碼轉(zhuǎn)變成機(jī)器可以執(zhí)行的指令

4. 鏈接(Linking)

  1. 詞法分析
    首先源代碼程序被輸入到掃描器(scanner),它運(yùn)用一種類似有限狀態(tài)機(jī)(Finite State Machine)的算法將源代碼的字符序列分割成一系列的記號(Token)
  2. 語法分析
    語法分析器(Grammar Parser)將對由掃描器產(chǎn)生的記號進(jìn)行語法分析,產(chǎn)生語法樹(Syntax Tree),整個過程采用長下文無關(guān)語法(Context-free Grammar)的分析手段。語法樹就是以表達(dá)式(Expression)為及節(jié)點(diǎn)的樹。
  3. 語義分析
    語義分析器(Semantic Analyer) 來完成。所能分析的語義是靜態(tài)語義(Static Semantic),通常包括聲明和類型的匹配、類型的轉(zhuǎn)換。
  4. 中間語言生成
    源碼級優(yōu)化器(Source Code Optimizer)將整個語法樹轉(zhuǎn)換成中間代碼(Intermediate Code)
  5. 目標(biāo)代碼的生成與優(yōu)化
    源代碼級優(yōu)化器產(chǎn)生中間代碼標(biāo)志著下面的過程都屬于編輯器后端,主要包括的代碼生成器(Code Generator)目標(biāo)優(yōu)化器(Target Code Optimizer)。代碼生成器將中間代碼轉(zhuǎn)換目標(biāo)機(jī)器碼。
  6. 鏈接
    鏈接的主要過程包括:地址和空間分配(Adress and Storage Allocation)符號決議(symbol resolution)重定向(Relocation)等步驟。

目標(biāo)文件是什么樣的

目標(biāo)文件的內(nèi)容至少有編譯后的機(jī)器指令代碼,數(shù)據(jù)。還有鏈接時所需要的信息,如符號表,調(diào)試信息,字符串等。

  • 程序源代碼編譯后的機(jī)器指令經(jīng)常被放在代碼段(Code Setion),常見名字有“.code”和 “.text”
  • 全局變量和局部靜態(tài)變量數(shù)據(jù)經(jīng)常放在數(shù)據(jù)段(Data Section),一般名字叫“.data”
  • .bss段(Block Started by Symbol)只是為未初始化的全局變量和局部靜態(tài)變量預(yù)留位置而已,并沒有內(nèi)容,它在文件中不占據(jù)空間。
自定義段

GCC提供了一個擴(kuò)展機(jī)制,使得程序員可以指定變量所處的段:

_attribute_((section("FOO"))) int global = 42;
_attribute_((section("Bar"))) void foo ( )
{
}

我們在全局變量或者函數(shù)之前加上“_attribute_((section("name")))”屬性就可以把相應(yīng)的變量或者函數(shù)放到以“name”作為段名的段中。

ELF文件結(jié)構(gòu)描述

ELF文件結(jié)構(gòu)圖

ELF Header
.text
.data
.bss
other sections...
Section header table
String Tables
Symbol Tables
...

靜態(tài)鏈接

1.空間與地址分配

主要有兩種方式:按序疊加和相似段合并。按序疊加會造成內(nèi)存空間大量的內(nèi)部碎片。所以一個更實(shí)際的方法是將相同性質(zhì)的段合并在一起,叫做相似段合并。比如將所有輸入文件的“.text”段合并到輸出文件的“.text”段。使用這相思段合并方法的鏈接器一般都采用一種叫兩步鏈接(Two-pass Linking)的方法,也就說整個過程分兩步。

  1. 空間與地址分配
  2. 符號解析與重定位

裝載與動態(tài)鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容