一個現代編譯器的主要工作流程如下:
源代碼(sourcecode)→預處理器(preprocessor)→編譯器(compiler)→彙編器(assembler)→目標代碼(objectcode)→連接器(Linker)→可執行程序(executables)
高級語言代碼 -----> 可執行二進制代碼 的4個階段:
預處理階階段:
- 主要是進行文本替換、宏展開、刪除註釋這類簡單工作。
- 通常得到以 .i 結尾的文件。
- 預處理之後,得到的僅僅是真正的源代碼,是高級語言。
編譯階段:
- 編譯器把高級語言翻譯爲機器語言。
- 得到 hello.s 文件,這個是彙編語言程序。
- 不同的高級語言翻譯的彙編語言相同。
彙編階段:
- 彙編器將hello.s翻譯成機器語言指令,把這些指令打包成可重定位目標程序。
- 得到.o文件,是一個二進制文件,它的字節碼是機器語言指令,不再是字符。前面兩個階段都還有字符。
鏈接階段:
- 鏈接器負責 .o 文件的合併。得到的是可執行目標文件。
- gcc會到系統默認的搜索路徑”/usr/lib”下進行查找,也就是鏈接到libc.so.6庫函數中去。 函數庫一般分爲靜態庫和動態庫兩種。
- 靜態庫是指編譯鏈接時,把庫文件的代碼全部加入到可執行文件中,因此生成的文件比較大,但在運行時也就不再需要庫文件了。其後綴名一般爲”.a”。
- 動態庫與之相反,在編譯鏈接時並沒有把庫文件的代碼加入到可執行文件中,而是在程序執行時由運行時鏈接文件加載庫,這樣可以節省系統的開銷。動態庫一般後綴名爲”.so”,如前面所述的libc.so.6就是動態庫。gcc在編譯時默認使用動態庫。
於是,帶着這個理解看2016年的一道命制的習題:
(2016.12)將高級語言源程序轉換爲機器目標代碼文件的程序是(C)
A. 彙編程序
B. 鏈接程序
C. 編譯程序
D. 解釋程序
分析:根據上面的描述,這裏需要明確的是機器目標代碼文件可不可以用來指代彙編程序文件。按照很多文章的解釋,這個就是指彙編程序文本。首先,經過彙編程序以後,得到的是可重定位的二進制目標程序,已經不再是含字符的文件了。此外,處理高級程序的一定是預處理程序或編譯程序。彙編處理的對象是彙編程序文本,鏈接處理的是可重定位二進制程序。因此,這裏就是在指代編譯程序。
之所以會猶豫是因爲,看到機器,很容易聯想到就是彙編或者鏈接之後的東西,這是很難拋開的一個概念障礙。