1. 程式人生 > >(轉)C++編譯過程詳解

(轉)C++編譯過程詳解

概念

1.編譯:把原始檔中的原始碼翻譯成機器語言,儲存到目標檔案中。如果編譯通過,就會把.C/.CPP轉換成.obj檔案Windows系統/.o(Linux系統)

2.編譯單元:每個.c/.cpp就是一個編譯單元,每個編譯單元相互之間是獨立且相互不知的。一個編譯單元(Translation Unit)是指一個.c/.cpp檔案以及它所include的所有.h檔案,.h檔案裡面的程式碼將會被擴充套件到包含它的.c/.cpp檔案裡,然後編譯器編譯該.c/.cpp檔案為一個.obj/.o檔案,後者擁有PE(Portable Executable,即Windows可執行檔案)檔案格式,並且本身包含的就是二進位制程式碼,但是不一定能執行,因為並不能保證其中一定有main函式。當編譯器將一個工程裡的所有.cpp檔案以分離的方式編譯完畢後,再由連結器進行連結成為一個庫檔案.lib、.dll檔案(Windows系統)/.a、.so檔案(Linux系統)或可執行檔案.exe。

3.目標檔案:編譯後生成的檔案,以機器碼的形式包含了編譯單元裡所有的函式和資料、匯出符號表、未解決符號表、地址重定向表。目標檔案型別包含有:可重定位檔案(.obj/.o)、共享的目標檔案(庫檔案)、可執行檔案。

        1)可重定位檔案(.obj/.o):其中包含有適合於其它目標檔案連結來建立一個可執行的或者共享的目標檔案的程式碼和資料每個.cpp會被編譯成一個.obj/.o檔案

        2)共享的目標檔案(庫檔案):靜態庫(.lib/.a)或動態庫(.dll/.so)

        3)可執行檔案:一個可以被作業系統建立一個程序來執行之的檔案

備註:.obj

/.o檔案在編譯後就能獲得,但是庫檔案、可執行檔案都需要在連結後才能獲得

c++程式編譯過程

整個程式編譯過程分為編譯連結兩個過程。

1.編譯過程:

作用:編譯是讀取源程式(字元流),對之進行詞法和語法的分析,將高階語言指令轉換為功能等效的彙編程式碼,再轉換為機器程式碼,生成目標檔案(.obj/.o)。

編譯分為兩個過程:編譯(預處理階段和編譯優化階段)、彙編。

        1)編譯:預處理階段:巨集#define;條件編譯指令,如#ifdef、#ifndef、#else、#elif、#endif等;標頭檔案包含,如#include <iostream>;特殊符號。

                      編譯、優化階段:針對程式碼優化,不依賴具體計算機;針對計算機優化。

        2)彙編:把組合語言程式碼翻譯成目標機器指令,生成目標檔案(.obj/.o),此過程會依賴機器的硬體和作業系統環境。

.obj/.o檔案至少要提供3張表:

        ① 匯出符號表:即該目標檔案可以提供的符號及地址;

        ② 未解決符號表:即找不到地址的符號的列表,告訴連結器這些符號沒找到地址;

        ③ 地址重定向表:連結的時候,連結器會為目標檔案的“未解決符號表”裡的符號在其他目標檔案中尋找地址,但是每個目標檔案的地址都是從0x0000開始的,這樣直接將對方檔案中符號的地址拿過來用顯然會是不正確的,為了區分不同的檔案,連結器在連結時就會對每個目標檔案的地址進行調整。在這個例子中,假如B.obj的0x0000被定位到可執行檔案的0x00001000上,而A.obj的0x0000被定位到可執行檔案的0x00002000上,那麼實現上對連結器來說,A.obj的匯出符號地地址都會加上0x00002000,B.obj所有的符號地址也會加上0x00001000,這樣就可以保證地址不會重複。因為被加上了起始地址,所以符號在自身檔案中的實際地址就不對了,需要再用一張地址重定向表記錄符號相對自身檔案的地址。

2.連結過程:

作用:連結程式的主要工作就是將有關的目標檔案(庫檔案、.obj/.o檔案)彼此相連線,也即將在一個檔案中引用的符號同該符號在另外一個檔案中的定義連線起來,使得所有的這些目標檔案成為一個能夠被作業系統裝入執行的統一整體。

具體工作:當連結器進行連結的時候,首先決定各個目標檔案在最終可執行檔案裡的位置。然後訪問所有目標檔案的地址重定義表,對其中記錄的地址進行重定向(加上一個偏移量,即該編譯單元在可執行檔案上的起始地址)。然後遍歷所有目標檔案的未解決符號表,並且在所有的匯出符號表裡查詢匹配的符號,並在未解決符號表中所記錄的位置上填寫實現地址。最後把所有的目標檔案的內容寫在各自的位置上,再作一些另的工作,就生成一個可執行檔案。

連結方式:靜態連結動態連結

        ① 靜態連結:函式的程式碼將從其所在的靜態連結庫中被拷貝到最終的可執行程式中,這樣該程式在被執行時這些程式碼將被裝入到該程序的虛擬地址空間中。

        ② 動態連結:函式的程式碼被放到稱作是動態連結庫或共享物件的某個目標檔案中,連結程式時所作的只是在最終的可執行程式中記錄下共享物件的名字以及其它少量的登記資訊,在此可執行檔案被執行時,動態連結庫的全部內容將被對映到執行時相應程序的虛地址空間,動態連結程式將根據可執行程式中記錄的資訊找到相應的函式程式碼。

        1)預處理:條件編譯,標頭檔案包含,巨集替換的處理,生成.i檔案;

        2)編譯:將預處理後的檔案轉換成組合語言,生成.s檔案;

        3)彙編:彙編變為目的碼(機器程式碼)生成.o的檔案;

        4)連結:連線目的碼,生成可執行程式。