LLVM
LLVM是架構(gòu)編譯器
(compiler)的框架系統(tǒng)申眼,由C++編寫完成,用于優(yōu)化
已任意程序編寫的程序的編譯時(shí)間
(compile-time)争拐、鏈接時(shí)間
(link-time)辰妙、運(yùn)行時(shí)間
(run-time)以及空閑時(shí)間
(idle-time),對(duì)開發(fā)者保持開放碉输,并兼容已有腳本
傳統(tǒng)編譯器設(shè)計(jì)
編譯器前端(Frontend):負(fù)責(zé)
解析源代碼
,它會(huì)進(jìn)行詞法分析
亭珍、語法分析敷钾、語義分析和檢查源代碼是否存在錯(cuò)誤,然后構(gòu)建抽象語法樹(Abstract Syntax Tree,AST)
肄梨,LLVM
會(huì)生成中間代碼
(intermediate representationIR
)優(yōu)化器(Optimizer):負(fù)責(zé)進(jìn)行各種
優(yōu)化
,改善代碼的運(yùn)行時(shí)間
众羡,例如消除冗余計(jì)算等后端(Backend)/代碼生成器(CodeGenerator):將
代碼映射到目標(biāo)指令集
。生成機(jī)器語言
纱控,并進(jìn)行機(jī)器相關(guān)的代碼優(yōu)化
iOS的編譯器架構(gòu)
OC/C/C++
使用的編譯器前端是Clang
,swift前端是Swift
舶掖,后端都是LLVM
,Clang
會(huì)生成中間代碼
(intermediate representation IR
)
LLVM設(shè)計(jì)
使用通用的代碼表示形式(IR)
眨攘,用來在編譯器中表示代碼的形式,所有LLVM可以為任何編程語言獨(dú)立編寫前端嚣州,并且可以為任意硬件架構(gòu)獨(dú)立編寫后端
Clang簡介
Clang
是LLVM項(xiàng)目中的子項(xiàng)目鲫售,基于LLVM架構(gòu)的輕量級(jí)編譯器
,誕生之初是為了替代GCC该肴,提高更快的編譯速度情竹。它是負(fù)責(zé)編譯C、C++匀哄、Object-C語言的編譯器秦效,在整個(gè)LLVM架構(gòu)中屬于編譯器前端
編譯流程
- 單獨(dú)新建一個(gè)
main.m
文件
int test(int a,int b){
return a + b + 3;
}
int main(int argc, const char * argv[]) {
int a = test(1, 2);
printf("%d",a);
return 0;[圖片上傳中...(image.png-1984f6-1624280414052-0)]
}
- 通過命令
clang -ccc-print-phases main.m
LLVM編譯流程
//輸入文件:找到源文件
+- 0: input, "main.m", objective-c
//預(yù)處理階段:處理包括宏的替換雏蛮,頭文件的導(dǎo)入
+- 1: preprocessor, {0}, objective-c-cpp-output
//編譯階段:進(jìn)行詞法、語法分析阱州,檢測語法是否正確挑秉,最終生成IR
+- 2: compiler, {1}, ir
//后端:LLVM會(huì)通過一個(gè)一個(gè)的Pass去優(yōu)化,每個(gè)Pass做些事情苔货,最終生成匯編代碼
+- 3: backend, {2}, assembler
//生成目標(biāo)文件
+- 4: assembler, {3}, object
//鏈接:鏈接需要的動(dòng)態(tài)庫和靜態(tài)庫犀概,生成可執(zhí)行文件
+- 5: linker, {4}, image
//通過不同的架構(gòu),生成對(duì)應(yīng)的可執(zhí)行文件
6: bind-arch, "x86_64", {5}, image
1夜惭、預(yù)處理階段
預(yù)處理階段是進(jìn)行宏的替換和頭文件的導(dǎo)入
姻灶,我們可以通過下面命令來查看導(dǎo)入和替換情況
//在終端直接查看替換結(jié)果
clang -E main.m
//生成對(duì)應(yīng)的文件查看替換后的源碼
clang -E main.m >> main2.m
-
typedef
給數(shù)據(jù)類型取別名時(shí),在預(yù)處理階段不會(huì)被替換
-
define
的取的別名在預(yù)處理階段會(huì)被替換
诈茧,所有我們可以用這方法來進(jìn)行關(guān)鍵代碼混淆木蹬,例如將關(guān)鍵類和方法用系統(tǒng)類似的名稱取別名
2、編譯階段
編譯階段主要是進(jìn)行:詞法若皱、語法分析和代碼錯(cuò)誤檢查
,然后生成中間代碼IR
(1)詞法分析
預(yù)處理完成后就會(huì)進(jìn)行詞法分析
尘颓,會(huì)把代碼切成一個(gè)個(gè)Token
走触,比如大小括號(hào),等于號(hào)還有字符串等
- 通過下面命令查看詞法分析后結(jié)果
clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
- 如果頭文件找不到疤苹,我們可以通過下面命令指定sdk
clang -isysroot (自己SDK路徑) -fmodules -fsyntax-only -Xclang -dump-tokens main.m
clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.1.sdk/ -fmodules -fsyntax-only -Xclang -dump-tokens main.m
(2)語法分析
驗(yàn)證語法是否正確
互广,在詞法分析的基礎(chǔ)上將單詞序列組合成各類語法短語,如程序卧土、語句惫皱、表達(dá)式等等,然后將所有節(jié)點(diǎn)組成抽象語法樹(Abstract Syntax Tree,AST)
尤莺。語法分析程序判斷源程序在結(jié)構(gòu)上是否正確
- 我們可以通過下面命令查看語法分析的結(jié)果
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
- 如果導(dǎo)入頭文件找不到媳谁,可以指定SDK
clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.1.sdk/ -fmodules -fsyntax-only -Xclang -ast-dump main.m
下面是幾個(gè)關(guān)鍵字的含義
- -FunctionDecl 函數(shù)
- -ParmVarDecl 參數(shù)
- -CallExpr 調(diào)用一個(gè)函數(shù)
- -BinaryOperator 運(yùn)算符
(3)生成中間代碼IR
代碼生成器(Code Generaltion)
會(huì)將語法樹自頂向下遍歷逐步翻譯成LLVM IR
晴音,OC代碼會(huì)在這一步進(jìn)行runtime的橋接:property合成缔杉,ARC處理等
- 我們可以通過下面命令生成.ll的文本文件或详,來查看IR代碼
clang -S -fobjc-arc -emit-llvm main.m
IR基本語法
@ 全局標(biāo)識(shí)
% 局部標(biāo)識(shí)
alloca 開辟空間
align 內(nèi)存對(duì)齊
i32 32bit,4個(gè)字節(jié)
store 寫入內(nèi)存
load 讀取數(shù)據(jù)
call 調(diào)用函數(shù)
ret 返回
- IR文件在OC中是可以進(jìn)行優(yōu)化的拣宏,一般設(shè)置是在
target - Build Setting - Optimization Level(優(yōu)化器等級(jí))
中設(shè)置勋乾。LLVM的優(yōu)化級(jí)別分別是-O0 -O1 -O2 -O3 -Os(第一個(gè)是大寫英文字母O)
嗡善,下面是帶優(yōu)化的生成中間代碼IR的命令
clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll
- xcode7以后開啟
bitcode
各吨,蘋果會(huì)做進(jìn)一步優(yōu)化揭蜒,生成.bc的中間代碼剔桨,我們通過優(yōu)化后的IR代碼生成.bc代碼
clang -emit-llvm -c main.ll -o main.bc
3瑰谜、后端
LLVM在后端主要是會(huì)通過一個(gè)個(gè)的Pass去優(yōu)化萨脑,每個(gè)Pass做一些事情饺饭,最終生成匯編代碼
- 我們通過最終的
.bc或者.ll代碼
生成匯編代碼
clang -S -fobjc-arc main.bc -o main.s
clang -S -fobjc-arc main.ll -o main.s
- 生成的匯編代碼也可以進(jìn)行優(yōu)化
clang -Os -S -fobjc-arc main.m -o main.s
4瘫俊、生成目標(biāo)文件
是匯編器以匯編代碼作為插入
军援,將匯編代碼轉(zhuǎn)換為機(jī)器代碼
胸哥,最后輸出目標(biāo)文件(object file)
clang -fmodules -c main.s -o main.o
- 通過nm命令,查看main.o中的符號(hào)
xcrun nm -nm main.o
-
external
表示這個(gè)符號(hào)是可以外部訪問
的 -
_printf
函數(shù)是一個(gè)是undefined 银酬、external
的 -
undefined
表示在當(dāng)前文件暫時(shí)找不到符號(hào)_printf
5揩瞪、鏈接
鏈接主要是鏈接需要的動(dòng)態(tài)庫和靜態(tài)庫
- 靜態(tài)庫和可執(zhí)行文件合并
- 動(dòng)態(tài)庫是獨(dú)立鏈接
鏈接器會(huì)吧編譯生成的.o文件
和(.dylib.a)文件
李破,生成一個(gè)mach-o文件
clang main.o -o main
查看鏈接后的符號(hào)
xcrun nm -nm main
如下所示嗤攻,其中undefined
表示會(huì)在運(yùn)行時(shí)進(jìn)行動(dòng)態(tài)綁定
6妇菱、綁定
綁定主要是通過不同的架構(gòu)暴区,生成對(duì)應(yīng)的mach-o格式可執(zhí)行文件