當(dāng)前位置:首頁 > 芯聞號 > 充電吧
[導(dǎo)讀]?這里并沒不是討論大學(xué)課程中所學(xué)的《編譯原理》,只是寫一些我自己對C++編譯器及鏈接器的工作原理的理解和看法吧,以我的水平,還達(dá)不到講解編譯原理(這個(gè)很復(fù)雜,大學(xué)時(shí)幾乎沒學(xué)明白)。要明白的幾個(gè)概念:?

?這里并沒不是討論大學(xué)課程中所學(xué)的《編譯原理》,只是寫一些我自己對C++編譯器及鏈接器的工作原理的理解和看法吧,以我的水平,還達(dá)不到講解編譯原理(這個(gè)很復(fù)雜,大學(xué)時(shí)幾乎沒學(xué)明白)。

要明白的幾個(gè)概念:

????1、編譯:編譯器對源文件進(jìn)行編譯,就是把源文件中的文本形式存在的源代碼翻譯成機(jī)器語言形式的目標(biāo)文件的過程,在這個(gè)過程中,編譯器會(huì)進(jìn)行一系列的語法檢查。如果編譯通過,就會(huì)把對應(yīng)的CPP轉(zhuǎn)換成OBJ文件。

????2、編譯單元:根據(jù)C++標(biāo)準(zhǔn),每一個(gè)CPP文件就是一個(gè)編譯單元。每個(gè)編譯單元之間是相互獨(dú)立并且互相不可知。

????3、目標(biāo)文件:由編譯所生成的文件,以機(jī)器碼的形式包含了編譯單元里所有的代碼和數(shù)據(jù),還有一些期他信息,如未解決符號表,導(dǎo)出符號表和地址重定向表等。目標(biāo)文件是以二進(jìn)制的形式存在的。

?

????根據(jù)C++標(biāo)準(zhǔn),一個(gè)編譯單元(Translation Unit)是指一個(gè).cpp文件以及這所include的所有.h文件,.h文件里面的代碼將會(huì)被擴(kuò)展到包含它的.cpp文件里,然后編譯器編譯該.cpp文件為一個(gè).obj文件,后者擁有PE(Portable Executable,即Windows可執(zhí)行文件)文件格式,并且本身包含的就是二進(jìn)制代碼,但是不一定能執(zhí)行,因?yàn)椴⒉荒鼙WC其中一定有main函數(shù)。當(dāng)編譯器將一個(gè)工程里的所有.cpp文件以分離的方式編譯完畢后,再由鏈接器進(jìn)行鏈接成為一個(gè).exe或.dll文件。

?

下面讓我們來分析一下編譯器的工作過程:

我們跳過語法分析,直接來到目標(biāo)文件的生成,假設(shè)我們有一個(gè)A.cpp文件,如下定義:

????int n = 1;

????void FunA()

????{

????????++n;

????}

?

????它編譯出來的目標(biāo)文件A.obj就會(huì)有一個(gè)區(qū)域(或者說是段),包含以上的數(shù)據(jù)和函數(shù),其中就有n、FunA,以文件偏移量形式給出可能就是下面這種情況:

????偏移量????內(nèi)容????長度

????0x0000????n???????4

????0x0004????FunA??????

????注意:這只是說明,與實(shí)際目標(biāo)文件的布局可能不一樣,??表示長度未知,目標(biāo)文件的各個(gè)數(shù)據(jù)可能不是連續(xù)的,也不一定是從0x0000開始。

????FunA函數(shù)的內(nèi)容可能如下:

????0x0004 inc DWORD PTR[0x0000]

????0x00?? ret

????這時(shí)++n已經(jīng)被翻譯成inc DWORD PTR[0x0000],也就是說把本單元0x0000位置的一個(gè)DWORD(4字節(jié))加1。

?

????有另外一個(gè)B.cpp文件,定義如下:

????extern int n;

????void FunB()

????{

????????++n;

????}

????它對應(yīng)的B.obj的二進(jìn)制應(yīng)該是:

????偏移量????內(nèi)容????長度

????0x0000????FunB??????

????這里為什么沒有n的空間呢,因?yàn)閚被聲明為extern,這個(gè)extern關(guān)鍵字就是告訴編譯器n已經(jīng)在別的編譯單元里定義了,在這個(gè)單元里就不要定義了。由于編譯單元之間是互不相關(guān)的,所以編譯器就不知道n究竟在哪里,所以在函數(shù)FunB就沒有辦法生成n的地址,那么函數(shù)FunB中就是這樣的:

????0x0000 inc DWORD PTR[????]

????0x00?? ret

????那怎么辦呢?這個(gè)工作就只能由鏈接器來完成了。

????為了能讓鏈接器知道哪些地方的地址沒有填好(也就是還????),那么目標(biāo)文件中就要有一個(gè)表來告訴鏈接器,這個(gè)表就是“未解決符號表”,也就是unresolved symbol table。同樣,提供n的目標(biāo)文件也要提供一個(gè)“導(dǎo)出符號表”也就是exprot symbol table,來告訴鏈接器自己可以提供哪些地址。

?

????好,到這里我們就已經(jīng)知道,一個(gè)目標(biāo)文件不僅要提供數(shù)據(jù)和二進(jìn)制代碼外,還至少要提供兩個(gè)表:未解決符號表和導(dǎo)出符號表,來告訴鏈接器自己需要什么和自己能提供些什么。那么這兩個(gè)表是怎么建立對應(yīng)關(guān)系的呢?這里就有一個(gè)新的概念:符號。在C/C++中,每一個(gè)變量及函數(shù)都會(huì)有自己的符號,如變量n的符號就是n,函數(shù)的符號會(huì)更加復(fù)雜,假設(shè)FunA的符號就是_FunA(根據(jù)編譯器不同而不同)。

????所以,

????A.obj的導(dǎo)出符號表為

????符號????地址

????n???????0x0000

????_FunA???0x0004

????未解決符號為空(因?yàn)樗麤]有引用別的編譯單元里的東西)。

????B.obj的導(dǎo)出符號表為

????符號????地址

????_FunB???0x0000

????未解決符號表為

????符號????地址

????n???????0x0001

????這個(gè)表告訴鏈接器,在本編譯單元0x0001位置有一個(gè)地址,該地址不明,但符號是n。

????在鏈接的時(shí)候,鏈接在B.obj中發(fā)現(xiàn)了未解決符號,就會(huì)在所有的編譯單元中的導(dǎo)出符號表去查找與這個(gè)未解決符號相匹配的符號名,如果找到,就把這個(gè)符號的地址填到B.obj的未解決符號的地址處。如果沒有找到,就會(huì)報(bào)鏈接錯(cuò)誤。在此例中,在A.obj中會(huì)找到符號n,就會(huì)把n的地址填到B.obj的0x0001處。

?

????但是,這里還會(huì)有一個(gè)問題,如果是這樣的話,B.obj的函數(shù)FunB的內(nèi)容就會(huì)變成inc DWORD PTR[0x000](因?yàn)閚在A.obj中的地址是0x0000),由于每個(gè)編譯單元的地址都是從0x0000開始,那么最終多個(gè)目標(biāo)文件鏈接時(shí)就會(huì)導(dǎo)致地址重復(fù)。所以鏈接器在鏈接時(shí)就會(huì)對每個(gè)目標(biāo)文件的地址進(jìn)行調(diào)整。在這個(gè)例子中,假如B.obj的0x0000被定位到可執(zhí)行文件的0x00001000上,而A.obj的0x0000被定位到可執(zhí)行文件的0x00002000上,那么實(shí)現(xiàn)上對鏈接器來說,A.obj的導(dǎo)出符號地地址都會(huì)加上0x00002000,B.obj所有的符號地址也會(huì)加上0x00001000。這樣就可以保證地址不會(huì)重復(fù)。

?

????既然n的地址會(huì)加上0x00002000,那么FunA中的inc DWORD PTR[0x0000]就是錯(cuò)誤的,所以目標(biāo)文件還要提供一個(gè)表,叫地址重定向表,address redirect table。

?

????總結(jié)一下:

????目標(biāo)文件至少要提供三個(gè)表:未解決符號表,導(dǎo)出符號表和地址重定向表。

????未解決符號表:列出了本單元里有引用但是不在本單元定義的符號及其出現(xiàn)的地址。

????導(dǎo)出符號表:提供了本編譯單元具有定義,并且可以提供給其他編譯單元使用的符號及其在本單元中的地址。

????地址重定向表:提供了本編譯單元所有對自身地址的引用記錄。

?

????鏈接器的工作順序:

????當(dāng)鏈接器進(jìn)行鏈接的時(shí)候,首先決定各個(gè)目標(biāo)文件在最終可執(zhí)行文件里的位置。然后訪問所有目標(biāo)文件的地址重定義表,對其中記錄的地址進(jìn)行重定向(加上一個(gè)偏移量,即該編譯單元在可執(zhí)行文件上的起始地址)。然后遍歷所有目標(biāo)文件的未解決符號表,并且在所有的導(dǎo)出符號表里查找匹配的符號,并在未解決符號表中所記錄的位置上填寫實(shí)現(xiàn)地址。最后把所有的目標(biāo)文件的內(nèi)容寫在各自的位置上,再作一些另的工作,就生成一個(gè)可執(zhí)行文件。

????說明:實(shí)現(xiàn)鏈接的時(shí)候會(huì)更加復(fù)雜,一般實(shí)現(xiàn)的目標(biāo)文件都會(huì)把數(shù)據(jù),代碼分成好向個(gè)區(qū),重定向按區(qū)進(jìn)行,但原理都是一樣的。

????明白了編譯器與鏈接器的工作原理后,對于一些鏈接錯(cuò)誤就容易解決了。

?

????下面再看一看C/C++中提供的一些特性:

????extern:這就是告訴編譯器,這個(gè)變量或函數(shù)在別的編譯單元里定義了,也就是要把這個(gè)符號放到未解決符號表里面去(外部鏈接)。

?

????static:如果該關(guān)鍵字位于全局函數(shù)或者變量的聲明前面,表明該編譯單元不導(dǎo)出這個(gè)函數(shù)或變量,因些這個(gè)符號不能在別的編譯單元中使用(內(nèi)部鏈接)。如果是static局部變量,則該變量的存儲方式和全局變量一樣,但是仍然不導(dǎo)出符號。

?

????默認(rèn)鏈接屬性:對于函數(shù)和變量,默認(rèn)鏈接是外部鏈接,對于const變量,默認(rèn)內(nèi)部鏈接。

外部鏈接的利弊:外部鏈接的符號在整個(gè)程序范圍內(nèi)都是可以使用的,這就要求其他編譯單元不能導(dǎo)出相同的符號(不然就會(huì)報(bào)duplicated external symbols)。

內(nèi)部鏈接的利弊:內(nèi)部鏈接的符號不能在別的編譯單元中使用。但不同的編譯單元可以擁有同樣的名稱的符號。

?

????為什么頭文件里一般只可以有聲明不能有定義:頭文件可以被多個(gè)編譯單元包含,如果頭文件里面有定義的話,那么每個(gè)包含這頭文件的編譯單元都會(huì)對同一個(gè)符號進(jìn)行定義,如果該符號為外部鏈接,則會(huì)導(dǎo)致duplicated external symbols鏈接錯(cuò)誤。

?

????為什么公共使用的內(nèi)聯(lián)函數(shù)要定義于頭文件里:因?yàn)榫幾g時(shí)編譯單元之間互不知道,如果內(nèi)聯(lián)被定義于.cpp文件中,編譯其他使用該函數(shù)的編譯單元的時(shí)候沒有辦法找到函數(shù)的定義,因些無法對函數(shù)進(jìn)行展開。所以如果內(nèi)聯(lián)函數(shù)定義于.cpp里,那么就只有這個(gè).cpp文件能使用它。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉