iOS-底層探索28:LLVM入門

iOS 底層探索 文章匯總

目錄


一、LLVM概述

LLVM是構(gòu)架編譯器(compiler)的框架系統(tǒng),以C+ +編寫而成,用于優(yōu)化以任意程序語言編寫的程序的編譯時(shí)間(compile- time)、鏈接時(shí)間(ink-time)、 運(yùn)行時(shí)間(run-time)以及空閑時(shí)間(idle-time),對(duì)開發(fā)者保持開放,并兼容已有腳本。LLVM計(jì)劃啟動(dòng)于2000年,最初由美國UIUC大學(xué)Chris Lattner博士主持開展。2006年Chris Lattner加盟Apple Inc.并致力于LLVMApple開發(fā)體系中的應(yīng)用。
Apple也是LLVM計(jì)劃的主要資助者。目前LLVM已經(jīng)被蘋果IOS開發(fā)工具、Xilinx Vivado、Facebook、Google等各大公司采用。

傳統(tǒng)編譯器設(shè)計(jì)

編譯器前端(Frontend)

編譯器前端的任務(wù)是解析源代碼。它會(huì)進(jìn)行:詞法分析,語法分析,語義分析,檢查源代碼是否存在錯(cuò)誤,然后構(gòu)建抽象語法樹(Abstract Syntax Tree,AST) ,LLVM的前端還會(huì)生成中間代碼(intermediate representation, IR)

優(yōu)化器(Optimizer)

優(yōu)化器負(fù)責(zé)進(jìn)行各種優(yōu)化,改善代碼的運(yùn)行時(shí)間,例如消除冗余計(jì)算等。優(yōu)化器接收和輸出均是IR。

后端(Backend) /代碼生成器(CodeGenerator)

將代碼映射到目標(biāo)指令集。生成機(jī)器語言,并且進(jìn)行機(jī)器相關(guān)的代碼優(yōu)化。

iOS的編譯器架構(gòu)

Objective C/C/C++使用的編譯器前端是Clang, SwiftSwift,后端都是LLVM。

LLVM的設(shè)計(jì)

當(dāng)編譯器決定支持多種源語言或多種硬件架構(gòu)時(shí),LLVM最重要的地方就來了。其他的編譯器如GCC,它方法非常成功,但由于它是作為整體應(yīng)用程序設(shè)計(jì)的,因此它們的用途受到了很大的限制。
LLVM設(shè)計(jì)的最重要方面是,使用通用的代碼表示形式(IR) ,它是用來在編譯器中表示代碼的形式。所以LLVM可以為任何編程語言獨(dú)立編寫前端,并且可以為任意硬件架構(gòu)獨(dú)立編寫后端。

Clang

ClangLLVM項(xiàng)目中的一個(gè)子項(xiàng)目。它是基于LLVM架構(gòu)的輕量級(jí)編譯器,誕生之初是為了替代GCC,提供更快的編譯速度。它是負(fù)責(zé)編譯C、C++、 Objecte-C語言的編譯器,它屬于整個(gè)LLVM架構(gòu)中的,編譯器前端。對(duì)于開發(fā)者來說,研究Clang可以給我們帶來很多好處。

二、編譯流程

0、通過命令打印源碼編譯的各個(gè)階段

clang -ccc-print-phases main.m

0: input, "main.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
5: linker, {4}, image
6: bind-arch, "x86_64", {5}, image

0:輸入文件:找到源文件。
1:預(yù)處理階段:這個(gè)過程處理包括宏的替換,頭文件的導(dǎo)入。
2:編譯階段:進(jìn)行詞法分析、語法分析、檢測(cè)語法是否正確,最終生成IR。
3:后端:這里L(fēng)LVM會(huì)通過一個(gè)一個(gè)的Pass去優(yōu)化,每個(gè)Pass做一些事情,最終生成匯編代碼。
4:生成目標(biāo)文件。
5:鏈接:鏈接需要的動(dòng)態(tài)庫和靜態(tài)庫,生成可執(zhí)行文件。
6:通過不同的架構(gòu),生成對(duì)應(yīng)的可執(zhí)行文件。

1、預(yù)處理階段

1.1、define

main.m中的代碼如下:

#import <stdio.h>
#define C 30

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int a = 10;
        int b = 10;
        printf("%d",a + b + C);
    }
    return 0;
}

執(zhí)行如下命令

clang -E main.m >> main2.m

執(zhí)行完畢可以看到頭文件的導(dǎo)入和宏的替換

main2.m
1.2、typedef
#import <stdio.h>
#define C 30

typedef int CJ_INT_64;

int main(int argc, const char * argv[]) {
    @autoreleasepool {  
        CJ_INT_64 a = 10;
        CJ_INT_64 b = 10;
        printf("%d",a + b + C);
    }
    return 0;
}

預(yù)處理

typedef int CJ_INT_64;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        CJ_INT_64 a = 10;
        CJ_INT_64 b = 10;
        printf("%d",a + b + 30);
    }
    return 0;
}

define用于給數(shù)據(jù)取別名(),預(yù)處理階段會(huì)被替換;typedef用于給類型取別名,預(yù)處理階段不會(huì)被替換。
define使用例子:由于會(huì)在預(yù)處理階段被替換,因此可用來給敏感的數(shù)據(jù)、方法、類名取別名,代碼混淆,方法加鹽等。eg:#define isVIP isxxxVxxxIxxxP

2、編譯階段

2.1、詞法分析

預(yù)處理完成后就會(huì)進(jìn)行詞法分析。這里會(huì)把代碼切成一個(gè)個(gè)Token,比如大小括號(hào),等于號(hào)還有字符串等。

clang - fmodules -fsyntax-only -Xclang -dump-tokens main.m

2.2、語法分析

詞法分析完成之后就是語法分析,它的任務(wù)是驗(yàn)證語法是否正確。在詞法分析的基礎(chǔ)上將單詞序列組合成各類語法短語,如“程序”, “語句”, “表達(dá)式”等等,然后將所有節(jié)點(diǎn)組成抽象語法樹(Abstract Syntax Tree, AST)。 語法分析程序判斷源程序在結(jié)構(gòu)上是否正確。

clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

如果導(dǎo)入頭文件找不到(比如導(dǎo)入Foundation.h或者UIKit.h),那么可以指定SDK

clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.2.sdk(自己S
DK路徑) -fmodules -fsyntax-only -Xclang -ast-dump main.m

2.3、生成中間代碼IR(intermediate representation )

完成以上步驟后就開始生成中間代碼IR了,代碼生成器(Code Generation)會(huì)
將語法樹自頂向下遍歷逐步翻譯成LLVM IR。通過下面命令可以生成.ll的文本文
件,查看IR代碼。

clang -S -fobjc-arc -emit-llvm main.m

Objective C代碼在這一步 會(huì)進(jìn)行runtime的橋接: property合成, ARC處理等

IR的基本語法

@全局標(biāo)識(shí)
%局部標(biāo)識(shí)
alloca開辟空間
align內(nèi)存對(duì)齊
i32 32個(gè)bit, 4個(gè)字節(jié)
store寫入內(nèi)存
load讀取數(shù)據(jù)
call調(diào)用函數(shù)
ret返回

IR的優(yōu)化

LLVM的優(yōu)化級(jí)別分別是-O0 -O1 -O2 -O3 -Os(第一個(gè)是大寫英文字母O)

clang -Os -S - fobjc-arc -emit-llvm main.m -o main.ll

bitCode

xcode7以后開啟bitcode蘋果會(huì)做進(jìn)一步的優(yōu)化。 生成.bc的中間代碼。
我們通過優(yōu)化后的IR代碼生成.bc代碼

clang -emit-llvm -c main.ll -o main.bc

3、生成匯編代碼

我們通過最終的.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)文件(匯編器)

目標(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. 0
(undefined) external_ _printf
000000000000000 (__ TEXT,_ text) external_test
00000000000000a (__ TEXT,_ text) external_main

_printf是一個(gè)是undefined external的。
undefined表示在當(dāng)前文件暫時(shí)找不到符號(hào)_printf
external表示這個(gè)符號(hào)是外部可以訪問的。

5、生成可執(zhí)行文件(鏈接)

鏈接器把編譯產(chǎn)生的.o文件和(.dylib.a)文件,生成一個(gè)mach-o文件。

clang main.o -o main

查看鏈接之后的符號(hào)

$xcrun nm -nm main
(undefined) external_ printf ( from libSystem)
(undefined) external dyld_ stub_ _binder (from libSystem)
0000000000000 (_ TEXT,_ text) [referenced dynamically] external_mh_execute_header
000000100000f6d (__ TEXT,_ text) external_ test
000000100000f77 (__ TEXT,_ text) external_ main
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評(píng)論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,923評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評(píng)論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,253評(píng)論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,801評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,023評(píng)論 0 285
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,530評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,494評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,639評(píng)論 1 366
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,890評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評(píng)論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,242評(píng)論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,626評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容