C++從源文件到可執行文件 & 目標文件 & 鏈接

C++從源文件到可執行文件的過程、

源代碼–>編譯預處理–>編譯–>優化–>彙編–>鏈接–>可執行文件

具體如下:

編譯預處理-宏、條件編譯指令-頭文件指令
讀取源程序,對其中的僞指令(以#開頭的指令)和特殊符號進行預處理。

宏定義指令:如#define Name TokenString #undef等。對於#define,預編譯所做的就是將程序中的Name全部替換成TokenString。對於後一個,則取消宏定義,使得字符串Name不被替換。
條件編譯指令:#ifdef #ifndef #else #elif #endif等。這些僞指令的引入使得程序員來區區別定義不同的宏來決定編譯對哪些代碼進行處理。預編譯程序根據有關的文件,將哪些不必要編譯的代碼過濾掉。
頭文件包含指令:#include 。預編譯程序將頭文件的定義統統加入到它所長生的輸出文件中,以供編譯文件使用。
特殊符號:預編譯可以識別一些預編譯符號。
編譯階段-主要是語法處理
經過預編譯處理的輸出文件中,將只有常量。如數字、字符串、變量的定義,以及語言的關鍵字,如main、if、while等。預編譯工作是通過詞法分析和語法分析,在確認所有的指令都符合語法規則後,將其翻譯成等價的中間代碼表示或者彙編代碼。

優化階段
優化處理是編譯系統中一項比較艱深的技術。它涉及到的問題不僅同編譯技術本身有關,而且同機器的硬件環境也有關係。優化一部分是對中間代碼的優化。這種優化不依賴於計算機。另一種優化則是針對目標代碼的生成進行。

對中間代碼的優化:刪除公共表達式、循環優化(強度削弱、代碼外提、已知代變量合併等)、無用賦值等。
對目標代碼的優化:同機器的硬件結構緊密相關,最主要考慮是如何充分利用機器的各個硬件寄存器存放的有關變量的值,以減少對於內存的訪問次數。另外,根據機器硬件執行指令的特點而對指令進行一些調整使目標代碼比較簡短,執行效率高。
彙編階段
彙編過程實際上是指吧彙編語言翻譯成目標機器指令的過程。

鏈接程序
由彙編程序生成的目標文件並不能立即被執行。
鏈接程序是將有關的目標文件批次鏈接,也即將一個文件中引用的符號同該符號所在的另外一個文件中的定義鏈接起來,使得所有的這些目標文件成爲一個能夠操作系統裝入執行的統一整體。

靜態鏈接:函數的代碼將從其他靜態鏈接庫中拷貝在最終的可執行文件。
動態鏈接:函數的代碼被放到成爲動態鏈接庫或共享對象的某個目標文件中。鏈接程序只是在最終可執行程序中記錄下共享對象的名字以及其他少量登記信息。
 

目標文件裏面是什麼?什麼結構?

編譯器編譯源代碼後生成的文件叫做目標文件。從文件結構上來講,目標文件已經是二進制文件。編譯是針對單個源文件的,有幾個源文件就會生成幾個目標文件,並且在生成過程中不受其他源文件的影響。也就是說,不管當前工程中有多少個源文件,編譯器每次只編譯一個源文件、生成一個目標文件。

鏈接是什麼?靜態鏈接、動態鏈接是什麼,它們具體做了什麼?

由彙編程序生成的目標文件並不能立即被執行。
鏈接程序是將有關的目標文件批次鏈接,也即將一個文件中引用的符號同該符號所在的另外一個文件中的定義鏈接起來,使得所有的這些目標文件成爲一個能夠操作系統裝入執行的統一整體。

靜態鏈接 在這種鏈接方式下,函數的代碼將從其所在地靜態鏈接庫中被拷貝到最終的可執行程序中。這樣該程序在被執行時這些代碼將被裝入到該進程的虛擬地址空間中。靜態鏈接庫實際上是一個目標文件的集合,其中的每個文件含有庫中的一個或者一組相關函數的代碼。(個人備註:靜態鏈接將鏈接庫的代碼複製到可執行程序中,使得可執行程序體積變大)

動態鏈接  在此種方式下,函數的代碼被放到稱作是動態鏈接庫或共享對象的某個目標文件中。鏈指鏈接階段僅僅只加入一些描述信息,而程序執行時再從系統中把相應動態庫加載到內存中去。鏈接程序此時所作的只是在最終的可執行程序中記錄下共享對象的名字以及其它少量的登記信息。在此可執行文件被執行時,動態鏈接庫的全部內容將被映射到運行時相應進程的虛地址空間。動態鏈接程序將根據可執行程序中記錄的信息找到相應的函數代碼。(個人備註:動態鏈接指的是需要鏈接的代碼放到一個共享對象中,共享對象映射到進程虛地址空間,鏈接程序記錄可執行程序將來需要用的代碼信息,根據這些信息迅速定位相應的代碼片段。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章