編譯和鏈接

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

1. 被隱藏了的過程

??當(dāng)我們使用gcc來編譯一個(gè)程序時(shí)困后,例如

gcc hello.c

??運(yùn)行結(jié)束后會(huì)生成一個(gè)可執(zhí)行文件如暖,事實(shí)上,該命令執(zhí)行成功的背后可分為四個(gè)步驟:預(yù)處理(Prepressing)編譯(Compilation)座咆、匯編(Assembly)鏈接(Linking)

1.1 預(yù)編譯

??預(yù)編譯主要處理那些源代碼文件中以“#”開始的預(yù)編譯指令绵载。比如“#include”饲梭、“#define”等,主要處理規(guī)則如下:

  • 將所有的“#define”刪除早歇,并且展開所有宏定義倾芝。
  • 處理所有條件預(yù)編譯指令,例如“#if”箭跳、“#else”晨另、“#endif”等。
  • 處理“#include”預(yù)編譯指令谱姓,將被包含的文件插入到該預(yù)編譯指令的位置借尿。這個(gè)過程是遞歸進(jìn)行的。
  • 刪除所有的注釋代碼屉来。
  • 添加行號(hào)和文件名標(biāo)識(shí)路翻,以便于編譯時(shí)編譯器產(chǎn)生調(diào)試用的行號(hào)信息及用于編譯時(shí)產(chǎn)生編譯錯(cuò)誤或警告時(shí)能顯示行號(hào)。
  • 保留所有的“#pragma”編譯器指令茄靠,因?yàn)榫幾g時(shí)編譯器須使用它們茂契。

1.2 編譯

??編譯就是把預(yù)處理后的文件進(jìn)行一系列詞法分析、語法分析慨绳、語義分析和優(yōu)化后生成相應(yīng)的匯編代碼文件掉冶。

1.3 匯編

??匯編器是將匯編代碼轉(zhuǎn)變成機(jī)器可以執(zhí)行的指令,每一條語句基本都對應(yīng)一條機(jī)器指令脐雪。

1.4 鏈接

??先關(guān)注一下上面的內(nèi)容郭蕉,再來分析鏈接過程。

2. 編譯器做了什么

??編譯過程一般可以分為6步:掃描喂江、語法分析召锈、語義分析、源代碼優(yōu)化获询、代碼生成和目標(biāo)代碼優(yōu)化涨岁。

2.1 詞法分析

??首先源代碼程序被輸入到掃描器,掃描器的任務(wù)很簡單吉嚣,它只是簡單地進(jìn)行詞法分析梢薪,運(yùn)用一種類似于有限狀態(tài)機(jī)的算法可以很輕松地將源代碼的字符序列分割成一系列的記號(hào)。這些記號(hào)一般分為如下幾類:關(guān)鍵字尝哆、標(biāo)識(shí)符秉撇、字面量(包含數(shù)字和字符串等)和特殊符號(hào)(如加號(hào)、等號(hào))。在識(shí)別記號(hào)的同時(shí)琐馆,掃描器也完成了其他工作规阀。比如將標(biāo)識(shí)符存放到符號(hào)表,將數(shù)字瘦麸、字符串常量存放到文字表等谁撼,已被后面的步驟使用。

2.2 語法分析

??接下來語法分析器將對掃描器產(chǎn)生的記號(hào)進(jìn)行語法分析滋饲,從而產(chǎn)生語法樹厉碟。整個(gè)分析過程采用了上下文無關(guān)語法的分析手段。簡單地講屠缭,由語法分析器產(chǎn)生的語法樹就是以表達(dá)式為節(jié)點(diǎn)的樹箍鼓。在這個(gè)階段,如果出現(xiàn)了表達(dá)式不合法呵曹,比如括號(hào)不匹配款咖,表達(dá)式中缺少操作符等,編譯器就會(huì)報(bào)告語法分析階段的錯(cuò)誤逢并。

2.3 語義分析

??語法分析器僅僅完成了對表達(dá)式的語法層面的分析之剧,但它并不了解這個(gè)語句是否真正有意義。比如C語言里面兩個(gè)指針做乘法運(yùn)算是沒有意義的砍聊,但是這個(gè)語句在語法上是合法的背稼,編譯器能夠分析的語義是靜態(tài)語義,所謂的靜態(tài)語義是指在編譯期可以確定的語義玻蝌,與之對應(yīng)的動(dòng)態(tài)語義就是只有在運(yùn)算期才能確定的語義蟹肘。
??靜態(tài)語義通常包括聲明和類型的匹配,類型的轉(zhuǎn)換俯树,比如當(dāng)一個(gè)浮點(diǎn)型的表達(dá)式轉(zhuǎn)換為一個(gè)整型的表達(dá)式時(shí)帘腹,其中隱含了一個(gè)從浮點(diǎn)型到整型的轉(zhuǎn)換過程许饿,語義分析中需要完成這個(gè)步驟阳欲。比如將一個(gè)浮點(diǎn)型賦值個(gè)一個(gè)指針時(shí),語義分析程序會(huì)發(fā)現(xiàn)這個(gè)類型不匹配陋率,編譯器將會(huì)報(bào)錯(cuò)球化。動(dòng)態(tài)語義一般指在運(yùn)行期出現(xiàn)的語義相關(guān)的問題,比如將0作為除數(shù)是一個(gè)運(yùn)行期語義錯(cuò)誤瓦糟。
??經(jīng)過語義分析之后筒愚,整個(gè)語法樹表達(dá)式都被標(biāo)識(shí)了類型,如果有些類型需要做隱式轉(zhuǎn)換菩浙,語義分析程序會(huì)在語法樹中插入相應(yīng)的轉(zhuǎn)換節(jié)點(diǎn)巢掺。

2.4 中間語言生成

??中間代碼是由源代碼優(yōu)化器通過轉(zhuǎn)化語法樹生成的句伶,它是語法樹的順序表示,已經(jīng)非常接近目標(biāo)代碼了陆淀。但是它一般跟目標(biāo)機(jī)器和運(yùn)行時(shí)環(huán)境是無關(guān)的考余,比如它不包含數(shù)據(jù)的尺寸、變量地址和寄存器的名字等倔约。中間代碼有多種類型秃殉,比較常見的有P-代碼三地址碼,最基本的三地址碼是這樣的:

x = y op z

??這個(gè)三地址碼表示將y和z進(jìn)行op操作后賦值給x坝初。
??假設(shè)存在代碼如下:

array[index] = (index + 4) * (2 + 6)

??這段代碼生成的語法樹轉(zhuǎn)換成中間代碼為:

t1 = 2 + 6
t2 = index + 4
t3 = t2 * t1
array[index] = t3

??為了使所有的操作都符合三地址碼形式浸剩,這里采用了幾個(gè)臨時(shí)變量:t1、t2和t3鳄袍,在三地址碼基礎(chǔ)上進(jìn)行優(yōu)化時(shí)绢要,優(yōu)化程序會(huì)將(2+6)的結(jié)果計(jì)算出來,得到t1=8拗小,然后將后面的t1替換為8重罪,還可以省去一個(gè)臨時(shí)變量t3,因?yàn)閠2可以重復(fù)使用哀九,經(jīng)過優(yōu)化以后的代碼如下:

t2 = index + 4
t2 = t2 * 8 
array[index] = t2

??中間代碼使得編譯器可以被分為前端和后端剿配。編譯器前端負(fù)責(zé)產(chǎn)生機(jī)器無關(guān)的中間代碼,編譯器后端將中間代碼轉(zhuǎn)換成目標(biāo)機(jī)器代碼阅束。這樣對于一些可以跨平臺(tái)的編譯器而言呼胚,它們可以針對不同的平臺(tái)使用同一個(gè)前端和針對不同機(jī)器平臺(tái)的數(shù)個(gè)后端。

2.5 目標(biāo)代碼生成和優(yōu)化

??源代碼級(jí)優(yōu)化器產(chǎn)生中間代碼標(biāo)志著下面的過程都屬于編輯器后端息裸。編譯器后端主要包括代碼生成器和目標(biāo)代碼優(yōu)化器蝇更。代碼生成器將中間代碼生成目標(biāo)機(jī)器代碼,這個(gè)過程十分依賴于目標(biāo)機(jī)器呼盆,因?yàn)椴煌瑱C(jī)器有著不同的字長年扩、寄存器、整數(shù)數(shù)據(jù)類型和浮點(diǎn)數(shù)數(shù)據(jù)類型等访圃。對于上面例子的中間代碼厨幻,代碼生成器可能會(huì)生成下面的代碼序列(用x86匯編語言表示):

movl index, %ecx          ;將index的值寫入ecx寄存器
addl $4, %ecx             ;ecx = ecx + 4
mull $8, %ecx             ;ecx = ecx * 8
movl index, %eax          ;將index的值寫入eax寄存器
movl %ecx, array(,eax,4)  ;array[index] = ecx

??最后目標(biāo)代碼優(yōu)化器對上述的目標(biāo)代碼進(jìn)行優(yōu)化,
腿时。况脆。。未完待續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末圈匆,一起剝皮案震驚了整個(gè)濱河市漠另,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌跃赚,老刑警劉巖笆搓,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件性湿,死亡現(xiàn)場離奇詭異,居然都是意外死亡满败,警方通過查閱死者的電腦和手機(jī)肤频,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來算墨,“玉大人宵荒,你說我怎么就攤上這事【秽郑” “怎么了报咳?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挖藏。 經(jīng)常有香客問我暑刃,道長,這世上最難降的妖魔是什么膜眠? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任岩臣,我火速辦了婚禮,結(jié)果婚禮上宵膨,老公的妹妹穿的比我還像新娘架谎。我一直安慰自己,他們只是感情好辟躏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布谷扣。 她就那樣靜靜地躺著,像睡著了一般鸿脓。 火紅的嫁衣襯著肌膚如雪抑钟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天野哭,我揣著相機(jī)與錄音在塔,去河邊找鬼。 笑死拨黔,一個(gè)胖子當(dāng)著我的面吹牛蛔溃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播篱蝇,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贺待,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了零截?” 一聲冷哼從身側(cè)響起麸塞,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涧衙,沒想到半個(gè)月后哪工,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奥此,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年雁比,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稚虎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡偎捎,死狀恐怖蠢终,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茴她,我是刑警寧澤寻拂,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站败京,受9級(jí)特大地震影響兜喻,放射性物質(zhì)發(fā)生泄漏梦染。R本人自食惡果不足惜赡麦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帕识。 院中可真熱鬧泛粹,春花似錦、人聲如沸肮疗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伪货。三九已至们衙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碱呼,已是汗流浹背蒙挑。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愚臀,地道東北人忆蚀。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像姑裂,于是被迫代替她去往敵國和親馋袜。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

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