利用ld.gold將程式編譯成llvm中的Bitcode

白馬負金羈發表於2017-07-20

LLVM是一個自由軟體專案,它是一種編譯器基礎設施,以C++寫成。其發端源於2000年伊利諾伊大學厄巴納-香檳分校(UIUC)的維克拉姆·艾夫(Vikram Adve)與其第一個博士生克里斯·拉特納(Chris Lattner)的研究,彼時他們想要為所有靜態及動態語言創造出動態的編譯技術。


LLVM的命名最早源自於底層虛擬機器(Low Level Virtual Machine)的首字母縮寫,但現在這個專案的範圍早已大大超越其最初的意思。當前,LLVM已經發展成為被用於開發從編譯器前端到後端的“一套模組及可重用的編譯器及工具鏈技術的集合”("collection of modular and reusable compiler and toolchain technologies")。


我們都知道,從原始碼到可執行檔案中,需要經過編譯和連結兩個主要過程。舉例來說,你試用GCC作為編譯器,那麼他會將將原始碼編譯為.o檔案,然後linker又會將.o連結為.so或者可執行程式(如果是在Linux中,即為ELF檔案),這裡我們所說的linker可以使用ld、ld.gold或者lld。


ld在binutils軟體包中,是最常用的linker;ld.gold也在binutils軟體包中,速度比ld快不少,它是一種仍然處在開發中的連結器;lld是llvm中預設使用的linker。在clang中使用ld.gold會實現很多意想不到的功能。例如,對於一些autotooled的軟體專案,各個檔案之間可能存在很強的依賴性,這時要想通過-emit-llvm的方法來得到IR檔案可能並不容易。於是,使用ld.gold就會變成一個不錯的選擇。


首先,來檢查一下你的電腦上是否已經安裝了ld.gold。例如,在筆者所使用的Ubuntu系統上,你可以用命令which來幫助你定位ld.gold。此外,你還需要驗證ld.gold是否接受外掛引數,如下所示:


如果你能夠看到-plugin: missing argument這條警告,那麼表明you have plugin support. If not, such as an “unknown option” error then you will either need to build gold or install a recent version of ld.bfd with plugin support and then build gold plugin.


接下來,你需要驗證你所安裝的LLVM中是否已經包含了gold plugin。你需要在你的LLVM資料夾中搜尋LLVMgold.so這個檔案。如果你的LLVM是直接安裝的已經編譯好的binaries,通常並不會自動包含這個外掛。如果你發現缺少LLVMgold.so這個檔案的話,那麼你需要重新編譯你的LLVM。


關於編譯LLVM原始碼的方法,你可以參考本部落格前面的文章[1]中。文獻[2]是演示利用Ninja來編譯LLVM的一個視訊,這裡為了演示,我們也使用這種方法。如下圖所示,最重要的一點就是,你需要從你的binutils資料夾中找到檔案plugin-api.h所在的路徑,然後把它賦值給引數DLLVM_BINUTILS_INCDIR。


使用上面的命令生成Makefile檔案,然後使用下面的命令來編譯及安裝。

$ ninja
$ ninja install

編譯過程需要一段時間(可能較長),完成之後,你就會在LLVM中找到LLVMgold.so這個檔案。接下來,我們可以來測試一下。首先,你可以先準備好一個C程式,例如名為test.c的檔案。By applying the -flto flag while compiling, you create an LLVM bitcode file instead of an object file. Then you need to pass the emit-llvm plugin option to the gold linker, so that it generates bitcode file instead of an executable. 文獻[4]中亦指出:You should produce bitcode files from clang with the option -flto. This flag will also cause clang to look for the gold plugin in the lib directory under its prefix and pass the -plugin option to ld. It will not look for an alternate linker, which is why you need gold to be the installed system linker in your path.


一個例項:編譯binutils


For general autotooled projects, there are a few key points to get the autotools to generate bitcode files. 讓我們以binutils為例來做一下演示。首先你要確定,系統中預設的編譯器已經被指定為clang 與 clang++。你可以在Terminal裡用下面的語句來指定編譯器

$ export CC=clang
$ export CXX=clang++

而我在自己的Ubuntu中,希望系統一直使用clang和clang++,所以通過修改.bashrc檔案的方式來做“永久性”的調整,具體來說,需要在該檔案的末尾加上下面這兩句(其中的路徑是我安裝clang和clang++的位置)
export CC=/home/airobot/installs/llvm-2017-12-15/bin/clang
export CXX=/home/airobot/installs/llvm-2017-12-15/bin/clang++
然後你可以用echo來驗證一下:


緊接著,像下面這樣配合你的環境引數:


注意,根據文獻[5]中給出的建議,我們知道在編譯不同程式時,可能需要做針對性的配置,例如disable shared library build. Build with staticly linked modules. 在本文所描述的例子中,我們僅實在最基本的預設配置,即直接輸入下面的命令:

$ ./configure
$ make

執行完畢後,你會發現binutils已經被編譯成功,而且我們還同時得到了所需的bc 檔案。這裡特別需要說明曾經,also-emit-llvm plugin option, 會用來 generated both an executable and a bitcode file。但是 also-emit-llvm option only supported getting the IR before optimizations,目前它已經被淘汰。It has been replaced with a more generic save-temps option that saves the IRboth before and after optimizations. 這也就是前面我們所使用的外掛選項引數的意義。



參考文獻與推薦閱讀材料

[1] http://blog.csdn.net/baimafujinji/article/details/78598658

[2] https://www.youtube.com/watch?v=uZI_Qla4pNA

[3] http://gbalats.github.io/2015/12/10/compiling-autotooled-projects-to-LLVM-bitcode.html

[4] http://llvm.org/docs/GoldPlugin.html

[5] https://ece.uwaterloo.ca/~lintan/courses/testing/llvm.html#bitcode




相關文章