iOS底層-29:LLVM

LLVM概述

LLVM是架構(gòu)編譯器(compiler)的框架系統(tǒng),以C++編寫而成徐绑,用于優(yōu)化以任意程序語言編寫的程序的編譯時間(compile-time)鏈接時間(link-time)運行時間(run-time)以及空閑時間(idle-time),對開發(fā)者保持開放劲厌,并兼容已有腳本。
LLVM計劃啟動于2000年听隐,最初由美國UIUC大學(xué)的Chris Latter博士支持開展补鼻。
2006Chris Latter加盟Apple Inc。并致力于LLVM在Apple開發(fā)體系中的應(yīng)用雅任。Apple也是LLVM計劃的主要資助者风范。
目前LLVM已經(jīng)被蘋果iOS開發(fā)工具Xilinx Vivado沪么、Facebook硼婿、Google等大公司采用。

傳統(tǒng)編譯器

  • 新建一個hello.c文件
#include <stdio.h>
int main (int a, char* argv[]){

        printf("hello \n");
        return 0;

}
  • clang hello.c


    桌面上會生成一個a.out文件

  • 通過file指令查看a.out

file a.out

a.out: Mach-O 64-bit executable x86_64

可以看到a.out是一個Mach-O格式的64位可執(zhí)行文件成玫,架構(gòu)是x86_64 模擬器可讀加酵。所以Mac電腦可以讀拳喻。

  • ./a.out哭当,執(zhí)行這個文件

    就會打印一個hello

編譯器就是將代碼,轉(zhuǎn)換成CPU能看懂的二進(jìn)制文件冗澈,這里的.out文件也是二進(jìn)制文件

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

編譯器前端(Frontend)
編譯器前端的任務(wù)是解析源代碼钦勘。他會進(jìn)行:詞法分析語法分析亚亲、語義分析彻采,檢查源代碼是否存在錯誤,然后構(gòu)建抽象語法樹(Abstract Syntax Tree捌归,AST)肛响,LLVM的前端還會生成中間代碼(intermediate representation,IR)惜索。

優(yōu)化器(Optimizer)
優(yōu)化器負(fù)責(zé)進(jìn)行各種優(yōu)化特笋。改善代碼的運行時間,例如消除冗余計算等巾兆。

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

iOS編譯器架構(gòu)

Objective-C/C/C++使用的編譯器前端是clang蔫磨,Swiftswift淘讥,后端都是LLVM

LLVM的設(shè)計

當(dāng)編譯器決定支持多種源語言或多種硬件架構(gòu)時堤如,LLVM最重要的地方就來了蒲列。其他的編譯器如GCC,它非常成功搀罢,但由于它是作為整體應(yīng)用程序設(shè)計的嫉嘀,因此他們的用途受到了很大的限制。

LLVM最重要的方面是魄揉,使用通用的代碼表示形式(IR)剪侮,它是用來在編譯器中表示代碼的形式。所以LLVM可以為任何編程語言獨立編寫前端洛退,并且可以為任意硬件架構(gòu)獨立編寫后端瓣俯。

clang

clangLLVM項目中的一個子項目。它是基于LLVM架構(gòu)的輕量級編譯器兵怯,誕生之初是為了替代GCC彩匕,提供更快的編譯速度。它是負(fù)責(zé)編譯C媒区、C++驼仪、Objective-C語言的編譯器,它屬于整個LLVM架構(gòu)中的袜漩,編譯器前端绪爸。對于開發(fā)者來說,研究clang可以給我們帶來很多好處宙攻。

編譯流程

通過命令可以打印源碼的編譯階段

  • 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

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

預(yù)處理階段
執(zhí)行如下命令

  • clang -E main.m
  • clang -E main.m >> xxxx.m

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

typedef int LY_INT_32 ; typedef不會被替換
#define isVip wee68990 可以用來做混淆

編譯階段

  • 詞法分析
    預(yù)處理完成后就會進(jìn)行詞法分析绒净。這里會把代碼切成一個個Token见咒,比如大小括號,等于號還有字符串等挂疆。

    • clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
      一個符號一個符號分析
  • 語法分析
    詞法分析完成之后就是語法分析改览,它的任務(wù)是驗證語法是否正確。在詞法分析的基礎(chǔ)上將單詞序列組合成各類語法短語缤言。如“程序”宝当,“語句”,“表達(dá)式等等”胆萧,然后將所有結(jié)點組成抽象語法樹(Abstract Syntax Tree, AST)庆揩。語法分析程序判斷程序在結(jié)構(gòu)上是否正確。

    • clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
      如果導(dǎo)入頭文件找不到跌穗,那么可以指定SDK
    • clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.2.sdk(自己SDK的路徑) -fmodules -fsyntax-only -Xclang -ast-dump main.m
  • 生成中間代碼IR(intermediate representation)
    完成以上步驟后就開始生成中間代碼IR了订晌,代碼生成器(Code Generation)會將語法樹自頂向下遍歷逐步翻譯成LLVM IR。通過下面的命令可以生成.ll的文本文件蚌吸,查看IR代碼锈拨。

    • clang -S -fobjc-arc -emit-llvm main.m
      Objective-C代碼在這一步會進(jìn)行runtime的橋接property合成ARC處理等羹唠。

IR的基本語法:

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

IR的優(yōu)化
LLVM的優(yōu)先級別分別是 -O0 -O1 -O2 -O3 -Os(第一個是大寫字母O)
-clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll

也可以在Xcode中可以設(shè)置

bitCode
Xcode7之后開啟bitCode,蘋果會做進(jìn)一步的優(yōu)化佩微。生成.bc的中間代碼缝彬。
我們通過優(yōu)化后的IR代碼生成.bc代碼

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

  • 生成匯編代碼
    我們通過最終的.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

  • 生成目標(biāo)文件(匯編器)
    目標(biāo)文件的生成,是以匯編器以匯編代碼作為輸入喊衫,將匯編代碼轉(zhuǎn)換為機器代碼跌造,最后輸出目標(biāo)文件(object file)。

    • clang -fmodules -c main.s -o main.o

通過nm命令族购,查看下main.o中的符號

$xcrun nm -nm main.o
(undefined) external _printf
0000000000000000 (__TEXT,__text) external _test
000000000000000a (__TEXT,__text) external _main

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

  • 生成可執(zhí)行文件(鏈接)
    鏈接器把編譯產(chǎn)生的.o文件和(.dylib .a)文件生成一個mach-O文件
    • clang main.o -o main

查看鏈接之后的符號

$xcrun nm -nm main
(undefined) external _printf (from libSystem)
(undefined) external dyld_stub_binder (from libSystem)
0000000100000000 (__TEXT,__text) [referenced dynamically] external __

mh_execute_header
000000100000f6d (__TEXT,__text) external _test
000000100000f77 (__TEXT,__text) external _main

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陵珍,一起剝皮案震驚了整個濱河市寝杖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌互纯,老刑警劉巖瑟幕,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡只盹,警方通過查閱死者的電腦和手機辣往,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殖卑,“玉大人站削,你說我怎么就攤上這事》趸” “怎么了许起?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長菩鲜。 經(jīng)常有香客問我园细,道長,這世上最難降的妖魔是什么接校? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任猛频,我火速辦了婚禮,結(jié)果婚禮上蛛勉,老公的妹妹穿的比我還像新娘伦乔。我一直安慰自己,他們只是感情好董习,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布烈和。 她就那樣靜靜地躺著,像睡著了一般皿淋。 火紅的嫁衣襯著肌膚如雪招刹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天窝趣,我揣著相機與錄音疯暑,去河邊找鬼。 笑死哑舒,一個胖子當(dāng)著我的面吹牛妇拯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洗鸵,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼越锈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了膘滨?” 一聲冷哼從身側(cè)響起甘凭,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎火邓,沒想到半個月后丹弱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體德撬,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年躲胳,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜓洪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡坯苹,死狀恐怖隆檀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情北滥,我是刑警寧澤刚操,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站再芋,受9級特大地震影響菊霜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜济赎,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一鉴逞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧司训,春花似錦构捡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至统扳,卻和暖如春喘帚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咒钟。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工吹由, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人朱嘴。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓倾鲫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萍嬉。 傳聞我的和親對象是個殘疾皇子乌昔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

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