llvm入門篇
首先介紹一下這個頻道。為什麼想要開這樣一個頻道,因為國內有關 llvm
的資料實在是太缺乏了,缺乏到什麼程度,沒有一本(中文)圖書是講 llvm
的,網上可以蒐集到的資料也非常的少,要麼就都是高深莫測,不適合新手入門,或者晦澀難懂的機器翻譯,佶屈聱牙,恍若天書。
另一方面,現在已經全面進入了移動網際網路時代,移動App的普及,帶來的App安全保護和加固方面的需求也愈發強烈,安全從業人員與黑產的對抗早已上升到編譯器層面, Native
級別的花指令、字串混淆和控制流混淆、虛擬機器等加固等產品的出現,為廠商保護自己的智慧財產權,提高產品的安全級別,提高被破解的難度和成本,做出了不可磨滅的貢獻。
更何況現在都 8102
年了,移動戰略那都是明日黃花,市面上最火熱的已經是 大資料
、 人工智慧
和 NPU
了。在人工智慧演算法陷入效能瓶頸,大家都在思考如何將硬體的特性發揮到極致的今天,在編譯器演算法的研究上花點功夫,提高軟硬體協同工作的效能,是今後未來晶片廠商所要關注的一個重點。這也是為什麼高通、英特爾、ARM、華為等晶片公司長期佔據著 llvm
基金會贊助商榜首的原因。
昨天碰巧看到知乎大神藍色剛剛出爐的一篇文章《手把手帶你遨遊TVM》(當然他也是 llvm
堅定地擁護者,寫了很多 llvm
的文章 ),介紹了多種 AI
訓練框架 Training
之後的結果在不同硬體上的 Inference
問題,如 Intel CPU / Intel GPU / ARM CPU / ARM GPU / NV GPU / FPGA / AI
晶片等,而要在這多種多樣的裝置中都保持一個高效的Inference效能,其實是一件很有挑戰的事情,這裡面就涉及到了軟硬體結合的問題,自古就是各種效能優化關注的重點問題。

讓我們回到主題上來,編譯器技術如此重要,國內資料卻如此缺乏。資料基本上全是英語,《編譯原理》本身也是一門 CS
專業需要到大三才會開始授學的專業課。而且說實話,國內的編譯原理的教育可以說是非常失敗的,學生上完課跟沒上一個樣的情況非常多,可能也跟連老師都沒有動手操作過一個編譯器有關。學生如果想要切實的學點知識的話,又面臨著資料匱乏的問題,惡性迴圈,如此往復。
所以迫切需要有人來打破這個僵局,這也是我做這個頻道的初衷,希望可以憑藉我們大家的力量,將 feicong@llvm
這個圈子做好、運營好、運轉好。我將在這個方向上持續地投入時間和精力,也希望大家可以支援我,加入到圈子中來,一起學習和討論 llvm
知識。編譯器是一門非常底層的技術,不管您是做科研、還是做框架,做開發、還是做安全,在編譯器方向有所建樹會為您的簡歷增光不少,評級評優也好,升職跳槽也好,會這門“手藝”都非常吃香,想象一下HR或者CTO或者技術leader拿著您的簡歷,上面寫著“熟悉 llvm
編譯器及編譯原理”的場景,hold住二面現場從未如此簡單。
這將是你這麼多年來,花的最值的五十塊錢!!

或者歡迎加我的微信(ID:fe1c0ng)或微博(id:非蟲)
我們將會從實際的操作和程式碼的角度出發,對以下主題進行剖析。

未來也打算開一些線下meetup和現場教學,當然圈內的你肯定是享有優先體驗權!還在等什麼?趕緊拿起微信掃一掃吧!
llvm
概論
起源與發展
LLVM
專案的起源也是來源於 Chris Lattner
個人對編譯器的興趣,這種模式在歐美非常普遍,比如 Linux
的誕生就是,當時還是大二學生的 大嘴巴 託瓦茲個人想要重新造一個 *nix
核心,結果一大堆人在群裡討論得津津有味,然後大家紛紛建言獻策。說明對 kernel
感興趣的人特別多,群眾基礎才是大基礎,群眾路線才是XXXXX,(此處省略馬哲課文獻100頁)。
同樣,很多大學生學完編譯原理( Complier Principles Technology & Tools
,龍書)之後,滿身才華沒有用武之地,(這渾身按耐不住的查克拉,是什麼感覺。。。)所以想要找點類似的事情幹,滿足一下自己的好奇心,在老外眼裡叫做 “hack something” ,當然這種文化在中國是沒有的, paper
、建模和導師是壓在莘莘學子身上不斷摩擦的三座大山。
越來越多的人提出了一大堆建議,並且還貢獻了一堆程式碼,對於歪果仁來說,你這裡做的不對,不指正你一下,是很難受的一件事情。所以越往後這個專案越來越大, bug
也越來越少,可用性越來越強,然後很多商業機構看到這裡這個編譯器實現的挺好的嘛,而且還是開源的,我們也是魯迅“拿來主義”的堅定奉行者,來來來,新來的你們仨,週末回家帶上筆記本哈~下週一我們就決定 "All IN" LLVM
!
其實在矽谷,很多高科技公司的創始人,本來就是學校的老師或教授。教授手下有幾家科技企業,簡直是矽谷教授的標配。教授看到越來越多的公司,在專案中使用 LLVM
編譯器,巧了馬上又要教龍書了(這本書封面是一批Dragon)(PS:外國文化的 Dragon
和中國龍不是一個物種)(龍書從1982年出版到現在,已經36年了,教授每年都要教),教授心裡想,教泥煤的教,龍書自己去看,我們來聊聊 LLVM
!這才是 8102
年編譯器該有的模樣!
學生們本來就頭很大,龍書裡其實啥都有,也啥都沒有,以前只能啃啃 GNU
的 gcc
,gcc的歷史跟龍書一樣悠久,那程式碼讀起來那個酸爽,就跟老奶奶的裹腳布一樣,同學們看一次吐一次。要不是因為其他沒得選,開源的(貌似)就它一個!而且使用最廣泛的也是它。儘管如此,長年累月積累下來的架構的更迭和設計的混亂,沒個教授或者博士的經驗,根本讀起來都費勁。
那難道就沒有一個現代一點的編譯器了麼?有,那就是llvm!
跟gcc比起來,llvm算是一個“人寫的”、“給人看的”編譯器。llvm清爽、乾淨、模組化,gcc用的是單體結構,這玩意兒已經不適合現代人來閱讀了。llvm用的 C++
,gcc用的c,哪個更現代化一目瞭然。學生們非常歡迎llvm,通過學習llvm來理解編譯原理往往事半功倍,倍兒輕鬆,用起來也得心應手,這才是llvm得以普及和迅速擴大影響的關鍵!llvm在學術界的成功可以說是實踐與理論之間差距不斷縮小的結果。
後來學生們走上了社會,比如去蘋果公司上班了,當然還是繼續使用llvm編譯器,這時候就涉及到了許可證的問題。gcc用的是GPL許可證,GPL是有名的病毒協議,一日GPL,終身GPL,你用了它的作品,你自己也得免費開源,那我還用你個毛,我產品都送你好了。這在商業環境下是不可能的,而llvm自己的協議,幾乎就是 ofollow,noindex">Do What The Fuck You Want To Do Lisence ,你可以 do what the fuck you want to do
,唯一的要求就是別忘了提一下他們的 LLVM lisence
。
在先進的“WTFPL” license幫助下,產業界迅速地扔掉了gcc,擁抱更加開放的、可以拿來隨便改的llvm,影響迅速擴大,2012年llvm被授予ACM軟體系統獎,正是對llvm的高度認可。反之由於產業界的高度認同及其回哺,llvm從學術界的懵懂、迅速成長為具有工業級穩定性、前所未有的成熟度和極高效率的編譯器。
趣聞: Chris Latter
本來只是想寫一個底層的虛擬機器,這也是 LLVM
名字的由來, low level virtual machine
,跟 Java
的 JVM
虛擬機器一樣,可是後來,llvm從來沒有被用作過虛擬機器,哪怕 LLVM
的名氣已經傳開了。所以人們決定仍然叫他 LLVM
,更多的時候只是當作“商標”一樣的感覺在使用,其實它跟虛擬機器沒有半毛錢關係。
LLVM的功能介紹
以 C/C++
為例,LLVM編譯系統包括以下內容:
- 一個良好的前端;
GCC 4.2解析器
能解析的語言,比如C,C ++,Objective-C,Fortran
等,它都能提供同能能力的支援;另外它還能支援一些GCC的擴充套件外掛。 - LLVM指令集的穩定實現;不管程式碼處於何種狀態,都可以在彙編(ASCII)和位元組碼(二進位制)之間自由轉換。
- 一個功能強大的
Pass
管理系統,它根據它們的依賴性自動對Pass
(包括分析,轉換和程式碼生成Pass)進行排序,並將它們管道化以提高效率。 - 廣泛的全域性標量優化。
- 包含豐富的分析和轉換的連結時過程優化框架,包括複雜的完整程式指標分析、呼叫圖構建以及對配置檔案引導優化的支援。
- 易於重定向的程式碼生成器,目前支援X86,X86-64,PowerPC,PowerPC-64,ARM,Thumb,SPARC,Alpha,CellSPU,MIPS,MSP430,SystemZ和XCore。
- Just-In-Time(JIT)即時編譯器,目前支援X86,X86-64,ARM,AArch64,Mips,SystemZ,PowerPC和PowerPC-64。
- 支援生成DWARF除錯資訊。
DWARF - Object files and linked products will use DWARF as the debug information format. [dwarf] DWARF with dSYM File - Object files and linked products will use DWARF as the debug information format, and Xcode will also produce a dSYM file containing the debug information from the individual object files (except that a dSYM file is not needed and will not be created for static library or object file products). [dwarf-with-dsym]
- 用於測試和生成除上面列出的目標之外的目標的本機程式碼的C後端。
- 與gprof類似的分析系統。
- 具有許多基準程式碼和應用程序的測試框架。
- API和除錯工具,以簡化LLVM元件的快速開發。

LLVM的強項
- LLVM使用具有嚴格定義語義的簡單低階語言。
- 它包括C和C++/Objective-C、Java,Scheme等眾多的前端(其中也有一部分處於開發之中
- 它包括一個優化器,支援標量、過程間、配置檔案驅動和一些簡單迴圈的優化。
- 它支援完整編譯模型,包括連結時,安裝時,執行時和離線優化。
- LLVM完全支援準確的垃圾回收。
- LLVM程式碼生成器由於擁強大的目標描述語言所以可以支援眾多架構。
- LLVM擁有豐富的文件,各種專案的介紹都非常豐富。
- 許多第三方使用者聲稱LLVM易於使用和開發。例如,Stacker前端(現已不再維護)是在4天內由一個對LLVM小白編寫的。此外,LLVM擁有很多幫助新手迅速上手的工具。
- LLVM正在積極開發中,並且不斷得到擴充套件,增強和改進。
- LLVM 的條款非常開放,幾乎是隨意使用,只要別忘了帶上他們的lisence就行。
- LLVM目前由多個商業公司使用,他們開發並貢獻了許多擴充套件和新功能。
LLVM適合哪些人
- 對C和C ++程式的編譯時,連結時(過程間)和執行時轉換感興趣的編譯器研究人員;
- 對可移植的,與語言無關的指令集和編譯框架感興趣的虛擬機器研究人員
- 對編譯器/硬體技術感興趣的架構研究員
- 對靜態分析或插樁技術感興趣的安全研究人員
- 想要快速開發編譯器原型的教師或開發人員
- 希望獲得更好效能的終端使用者開發者
llvm
安裝和編譯
我們聊一下從原始碼環境中編譯生成 llvm
套件的可執行檔案。這種方式對於深入學習 llvm
的讀者來說,是必須要掌握的。
下載原始碼,然後使用編譯工具進行編譯。編譯工具可以是 llvm
,也可以是 gcc
。我們分別介紹一下。
原始碼在 releases.llvm.org/download.ht… 官網進行下載:

macOS
:使用 llvm
單獨編譯 llvm
llvm
與 clang
都作為單獨的元件以開源形式提供,可以單獨編譯它們,也可以組全在一起編譯。我們先來看下,如何單獨編譯 llvm
。
執行如下命令,下載與解壓 llvm
的原始碼。
$ wget http://releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz --2018-10-23 22:02:46--http://releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz 正在解析主機 releases.llvm.org (releases.llvm.org)... 151.101.42.49, 2a04:4e42:6::561 正在連線 releases.llvm.org (releases.llvm.org)|151.101.42.49|:80... 已連線。 已發出 HTTP 請求,正在等待迴應... 302 Found 位置:http://117.143.109.133/cache/releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz?ich_args2=139-23220102015663_6b4dad2fb2c1b96f7fc8786bd843192d_10001002_9c89602cd4c3f2d2973a518939a83798_c6988e40d0518b9e703b7a4f6f4dd23a [跟隨至新的 URL] --2018-10-23 22:02:47--http://117.143.109.133/cache/releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz?ich_args2=139-23220102015663_6b4dad2fb2c1b96f7fc8786bd843192d_10001002_9c89602cd4c3f2d2973a518939a83798_c6988e40d0518b9e703b7a4f6f4dd23a 正在連線 117.143.109.133:80... 已連線。 已發出 HTTP 請求,正在等待迴應... 200 OK 長度:28324368 (27M) [application/octet-stream] 正在儲存至: “llvm-7.0.0.src.tar.xz” llvm-7.0.0.src.tar.xz21%[======================>]5.86M1.08MB/s剩餘 21s $ tar -xvfllvm-7.0.0.src.tar.xz 複製程式碼
注意:編譯不可以在解壓後的資料夾內部編譯,需要在外部新建一個資料夾,否則編譯會失敗!
執行以下命令,新建mybuilder目錄,並進行編譯配置。
$ mkdir mybuilder $ cd mybuilder $ cmake ../llvm-7.0.0.src/ 複製程式碼
PS:如果沒有 cmake
可以先用 brew install cmake
安裝一下,然後再執行 cmake
命令。

然後再執行以下命令開始編譯:
$ cmake --build 複製程式碼

然後就開始編譯了。

CPU佔用率一直不高,穩定在比較低的狀態。一直到結束都不高,大概需要一小時左右。

完成之後進來看看:
$ cd bin $ ls FileCheckllvm-catllvm-dwpllvm-modextractllvm-readobjnot bugpointllvm-cfi-verifyllvm-exegesisllvm-mtllvm-rtdyldobj2yaml countllvm-configllvm-extractllvm-nmllvm-sizeopt dsymutilllvm-covllvm-gollvm-objcopyllvm-special-case-list-fuzzersancov llcllvm-cvtresllvm-isel-fuzzerllvm-objdumpllvm-splitsanstats llillvm-cxxdumpllvm-libllvm-opt-fuzzerllvm-stressverify-uselistorder lli-child-targetllvm-cxxfiltllvm-linkllvm-opt-reportllvm-stringsyaml-bench llvm-PerfectShufflellvm-demangle-fuzzerllvm-litllvm-pdbutilllvm-stripyaml2obj llvm-arllvm-diffllvm-ltollvm-profdatallvm-symbolizer llvm-asllvm-disllvm-lto2llvm-ranlibllvm-tblgen llvm-bcanalyzerllvm-dlltoolllvm-mcllvm-rcllvm-undname llvm-c-testllvm-dwarfdumpllvm-mcallvm-readelfllvm-xray $ ./llvm-as -version LLVM (http://llvm.org/): LLVM version 7.0.0 DEBUG build with assertions. Default target: x86_64-apple-darwin16.7.0 Host CPU: broadwell 複製程式碼
當然, llvm
後端要配合 clang
前端才能使用, clang
前端的編譯方法也跟 llvm
類似。
macOS
:使用 llvm
混合編譯 llvm
&& clang
大部分流程跟上文中 macOS
系統下用 llvm
編譯過程類似,首先下載 llvm
和 clang
的原始碼包並解壓,把解壓後的 clang
的原始碼包重新命名,並移動到 llvm-7.0.0.src/tools/
目錄下,最終效果為 llvm-7.0.0.src/tools/clang/
。
然後在build資料夾裡執行 $ cmake -G "Unix Makefiles" ../llvm-7.0.0.src
命令, cmake
會檢查編譯環境,如果沒有報錯(有報錯的解決報錯),直接執行 make
命令即可開始編譯。

編譯完成之後,在 build/bin/目錄下,即可找到
llvm 和
clang`的工具。
$ ls FileCheckllcllvm-gollvm-size arcmt-testllillvm-isel-fuzzerllvm-special-case-list-fuzzer bugpointlli-child-targetllvm-libllvm-split c-arcmt-testllvm-PerfectShufflellvm-linkllvm-stress c-index-testllvm-arllvm-litllvm-strings clangllvm-asllvm-ltollvm-strip clang++llvm-bcanalyzerllvm-lto2llvm-symbolizer clang-7llvm-c-testllvm-mcllvm-tblgen clang-checkllvm-catllvm-mcallvm-undname clang-clllvm-cfi-verifyllvm-modextractllvm-xray clang-cppllvm-configllvm-mtnot clang-diffllvm-covllvm-nmobj2yaml clang-formatllvm-cvtresllvm-objcopyopt clang-func-mappingllvm-cxxdumpllvm-objdumpsancov clang-import-testllvm-cxxfiltllvm-opt-fuzzersanstats clang-offload-bundlerllvm-demangle-fuzzerllvm-opt-reportscan-build clang-refactorllvm-diffllvm-pdbutilscan-view clang-renamellvm-disllvm-profdataset-xcode-analyzer clang-tblgenllvm-dlltoolllvm-ranlibverify-uselistorder countllvm-dwarfdumpllvm-rcyaml-bench diagtoolllvm-dwpllvm-readelfyaml2obj dsymutilllvm-exegesisllvm-readobj hmaptoolllvm-extractllvm-rtdyld $ ./clang --version clang version 7.0.0 (tags/RELEASE_700/final) Target: x86_64-apple-darwin16.7.0 Thread model: posix InstalledDir: /Users/userid/Desktop/mybuilder/bin/. 複製程式碼