編譯流程和llvm架構介紹


    第一部分 編譯流程介紹

    程序從源文件變成二進制可執行文件主要分為4個步驟:預編譯、編譯、匯編、鏈接。文件的格式變化為mian.c(源文件) -> main.i(預編譯后的文件) -> main.s(編譯后的文件,即匯編代碼) -> main.o(匯編后的文件) -> main.exe(二進制可執行文件)。

    我們廣義上將實現源文件轉變為可執行文件的機器稱為編譯器,但其實該過程主要是由四個不同的機器實現的,包括預處理器(CPP)、編譯器(CCL)、匯編器(AS)、鏈接器(LD)。

    預處理器:主要是將源文件中的頭文件編譯進來,進行宏替換,去掉注釋等,並將預處理后的代碼交給編譯器處理。

    編譯器

           1. 詞法分析階段:讀入經過預編譯處理后的源程序,對構成源程序的字符流進行掃描和分解,識別出單詞。

           2. 語法分析階段:機器通過詞法分析,將單詞序列分解成不同的語法短語,確定整個輸入串能夠構成語法上正確的程序。

           3. 語義分析階段:檢查源程序上有沒有語義錯誤(賦值語句左端與右端類型不匹配),在代碼生成階段收集類型信息。

           4. 中間代碼生成階段:在進行了上述的語法分析和語義分析階段的工作之后(前面三個分析階段主要是為了檢查程序中是否由錯誤,只有當程序沒有基礎錯誤才能將其轉變為中間代碼),有的編譯程序將源程序變成一種內部表示形式。

           5. 代碼優化:這一階段的任務是對前一階段產生的中間代碼進行變換或進行改造,目的是使生成的目標代碼更為高效,即省時間和省空間。

           6. 目標代碼生成:這一階段的任務是把中間代碼變換成特定機器上的絕對指令代碼或可重定位的指令代碼或匯編指令代碼(生成絕對指令代碼則相當於編譯器把AS和LD的功能都實現了,可以理解為這個編譯器中包含了匯編器和鏈接器的功能)。

    匯編器:將匯編代碼轉變為二進制可執行文件,匯編代碼的每一個指令都對應一個指定的二進制字符,前輩們就是覺得直接看二進制代碼太痛苦了所以將二進制字符抽象為匯編指令。

    鏈接器:實現符號重定位功能,將main.o中所依賴的所有外部文件全部鏈接到main中形成main.exe。相對於靜態鏈接,動態鏈接可以節省內存和磁盤空間、程序之間的耦合度小、適合大規模軟件開發、增加程序的可擴展性與兼容性,但是靜態鏈接部署和遷移相對來說更加方便。

    編譯原理中的前后端的區分應該是處理的代碼是否與目標機器有關,處理操作與目標機器無關的稱之為前端,與目標機器有關的那一部分操作稱之為后端。所以以這種方式來區分的話,預處理階段+編譯階段的詞法、語法、語義分析、中間代碼生成和代碼優化可以稱為前端,而編譯階段中的匯編代碼生成部分+匯編階段+鏈接階段可以稱為后端。

    

    第二部分 llvm及相關編譯器架構介紹

    傳統靜態編譯器(與大多數 C 編譯器一樣)最流行的設計是三相設計,其主要組件是前端、優化器和后端,其結構如下圖所示:

    

    當編譯器決定支持多種源語言或目標體系結構時,這種經典設計最重要的勝利就來了。如果編譯器在其優化器中使用通用代碼表示形式,則可以為可以編譯到它的任何語言編寫前端,也可以為可以從中編譯的任何目標編寫前端,結構如下圖所示:

    

    GCC(GNU Compiler Collection,GNU編譯器套件)也將三段式做的比較好,並且實現了很多前端,支持了很多語言。但是上述這些編譯器的致命缺陷是,他們是一個完整的可執行文件,沒有給其它語言的開發者提供代碼重用的接口。即使GCC是開源的,但是源代碼重用的難度也比較大,而llvm則可以解決這些問題。

    Clang 是一個 C、C++、Objective-C 和 Objective-C++ 編程語言的編譯器前端,采用底層虛擬機(LLVM)作為后端。

    LLVM 命名最早源自於底層虛擬機(Low Level Virtual Machine)的縮寫,由於命名帶來的混亂,目前LLVM就是該項目的全稱。LLVM 核心庫提供了與編譯器相關的支持,可以作為多種語言編譯器的后台來使用。能夠進行程序語言的編譯期優化、鏈接優化、在線編譯優化、代碼生成。LLVM的項目是一個模塊化和可重復使用的編譯器和工具技術的集合。輸入LLVM Optimizer優化器中的是LLVM IR中間語言,任何語言只要實現與之對應的前端將其源代碼翻譯為LLVM IR中間代碼,LLVM架構后端都能將其編譯程成相應的二進制文件在目標機器上運行。

    LLVM 架構是作用於編譯器中的,其結構如下如所示;

        

    java虛擬機一次編譯可以到處運行的原理是,java前端編譯器將java源代碼翻譯為Java bytecode,這是一種中間語言,可以被java虛擬機所識別。java虛擬機將中間代碼優化后再依據其所在機器的架構將其編譯為對應的二進制文件。如此就可以實現一次編譯多處運行。

 

參考鏈接:

https://www.cnblogs.com/zuopeng/p/4141467.html

http://www.aosabook.org/en/llvm.html

https://blog.csdn.net/xhhjin/article/details/81164076

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM