LLVM初探

編譯 想必都知道,那么LLVM是什么邢滑?
LLVM是一種編譯器!LLVM編譯流程是怎么樣的困后?
本篇就LLVM進(jìn)行初探

首先讓我們來了解編譯器是神馬~

一、編譯器是什么摇予?

1汽绢、以python程序?yàn)槔?br> 新建一個(gè)python文件:helloDemo.py(內(nèi)部一行代碼打印hello)

print("hello\n")

進(jìn)入python文件侧戴,執(zhí)行python helloDemo.py

image.png

2、c語言程序?yàn)槔?br> 新建helloDemo.c文件:

#include <stdio.h>
int main(int a,char * argv[]){
        printf("hello \n");
        return 0;
}

執(zhí)行clang helloDemo.c編譯积仗,生成a.out文件蜕猫,file a.out查看文件

image.png

發(fā)現(xiàn)最終生成文件是:.out文件:64位的Mach-O可執(zhí)行文件,當(dāng)前clang出來的是x86_64架構(gòu)隆圆, 說明mac電腦可讀。 所以可以./a.out直接執(zhí)行:


image.png

以上可以看到,python和C輸出流程是完全不同的租漂,pthyon直接用python命令就可以輸出結(jié)果哩治,而C需要先生成.out文件。這是由于兩種編譯過程不一樣

  • python是解釋型語言业筏,一邊翻譯一邊執(zhí)行蒜胖,機(jī)器可直接執(zhí)行。
  • C語言是編譯型語言寻狂,不可以直接執(zhí)行朋沮,需要編譯器將其轉(zhuǎn)換成機(jī)器識(shí)別語言。

注:
編譯型語言:編譯后輸出的是指令(0纠亚、1組合)筋夏,cpu可直接執(zhí)行指令
解釋性語言:生成的是數(shù)據(jù),不是0条篷、1組合拥娄,機(jī)器也能直接識(shí)別

  • 編譯器就是將高級(jí)語言轉(zhuǎn)換成機(jī)器可識(shí)別的語言可執(zhí)行文件

補(bǔ):
匯編語言是否需要編譯?
直接解釋
1牡昆、早期科學(xué)家,就是使用0丢烘、1編程播瞳。 為了摒棄手敲0和1的繁瑣。開發(fā)者們創(chuàng)造了中間解釋器赢乓,再創(chuàng)建出call牌芋、bl等這種容易記的指令來代表0、1組合(例如call對(duì)應(yīng)00001111)躺屁。有了對(duì)應(yīng)關(guān)系后犀暑,就好辦了。程序員只用輸入call耐亏、bl這樣的標(biāo)記指令苹熏,經(jīng)過解釋器,變成0和1的組合袱耽,就可以直接交給機(jī)器去執(zhí)行了干发。 這就是匯編的由來。
2枉长、基于匯編以上必峰,再映射和封裝相關(guān)對(duì)應(yīng)關(guān)系。于是生成了跨時(shí)代性的c語言吼蚁,再往上層封裝,就出現(xiàn)了高級(jí)語言oc粒蜈、swift、JAVA等語言注整。之所以匯編執(zhí)行快度硝,是因?yàn)樗苯愚D(zhuǎn)換為機(jī)器語塘淑。
3蚂斤、既然匯編速度這么快,為什么不都用匯編開發(fā)捌治?
因?yàn)閰R編的指令集纽窟,是針對(duì)同一操作系統(tǒng)而言,不支持跨平臺(tái)森枪。機(jī)器指令是cpu的在識(shí)別审孽。早期的計(jì)算機(jī)廠家非常多,雖然都用0和1的組合式散,但相同組合背后卻是相應(yīng)不同的指令打颤。所以匯編無法跨平臺(tái),不同操作系統(tǒng)下编饺,匯編指令是不同的透且,所以需要可以跨平臺(tái)的高級(jí)語言來開發(fā)~

二、LLVM概述

1、上面我們知道了編譯器是什么畅形。那么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ā)者保持開放第美,并兼任已有腳本
  • 2006年Chris Lattner加盟Apple Inc.并致力于LLVM在Apple開發(fā)體系中的應(yīng)用陆爽。Apple也是LLVM計(jì)劃的主要資助者慌闭。
    目前LLVM已經(jīng)被蘋果iOS開發(fā)工具、Xilinx Vivado兔港、Facebook仔拟、Google等各大公司采用

2、傳統(tǒng)編譯器


image.png
  • 編譯器前端(Frontend)

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

  • 優(yōu)化器(Optimizer)

優(yōu)化器負(fù)責(zé)各種優(yōu)化改善代碼的運(yùn)行時(shí)間蔼两,如消除冗余計(jì)算

源代碼中有很多函數(shù)調(diào)用额划,就會(huì)需要需要申請(qǐng)很多函數(shù)調(diào)用椀翟螅空間,調(diào)用函數(shù)棧時(shí)品抽,需要壓棧輸入數(shù)據(jù)甜熔,調(diào)用完畢后腔稀,出棧羽历。其中過程邏輯可能非常復(fù)雜,那么就會(huì)無形中就會(huì)占用很多內(nèi)存诵闭,優(yōu)化器就是用來優(yōu)化一些邏輯澎嚣,以節(jié)省時(shí)間和空間易桃。

  • 后端(Backkend)/ 代碼生成器(CodeGenerator)

將代碼映射到目標(biāo)指令集生成機(jī)器語言敌呈,并進(jìn)行機(jī)器相關(guān)的代碼優(yōu)化 (目標(biāo)指不同操作系統(tǒng))

3、iOS的編譯器架構(gòu)
Objective-C吭练、C褐鸥、C++編譯器的前端用的都是Clang,Swift使用的是swift叫榕,后端使用的是llvm

image.png
三、LLVM的設(shè)計(jì)

1寓落、llvm:支持多種語言多種硬件架構(gòu)荞下。使用通用代碼表示形式:IR(用來在編譯器中表示代碼的形式)
??GCC也是一個(gè)非常成功的編譯器尖昏,但由于它作為整體應(yīng)用程序設(shè)計(jì)的,用途受到了限制
因?yàn)?code>llvm使用IR作為中間文件,所以

  • LLVM可以為任何編程語言獨(dú)立編寫前端陨簇,也可以為任何硬件架構(gòu)獨(dú)立編寫后端.

  • LLVM是一個(gè)簡(jiǎn)單編譯器迹淌,而是架構(gòu)編譯器唉窃,可以兼容所有前端后端

    image.png

2苟跪、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可以給我們帶來很出益處

下面就Clang分析一下OC編譯流程

3虐唠、編譯流程

  • 新建一個(gè).m文件


    image.png
  • 進(jìn)入文件Test2
    執(zhí)行命令clang -ccc-print-phases main.m

    image.png

此步驟為7步驟
0: 輸入文件:找到源文件
1: 預(yù)處理:宏的展開疆偿,頭文件的導(dǎo)入
2: 編譯:詞法杆故、語法溉愁、語義分析,最終生成IR
3: 匯編: LLVM通過一個(gè)個(gè)的Pass去優(yōu)化罢缸,每個(gè)Pass做一些事投队,最后生成匯編代碼
4: 生成 目標(biāo)文件
5: 鏈接: 鏈接需要的動(dòng)態(tài)庫和靜態(tài)庫敷鸦,生成可執(zhí)行文件
6:架構(gòu)可執(zhí)行文件:通過不同架構(gòu)寝贡,生成對(duì)應(yīng)的可執(zhí)行文件
這里并沒有出現(xiàn)optimizer優(yōu)化器,因?yàn)樗仟?dú)立觸發(fā)碟案,與流程階段無關(guān)

  • 預(yù)處理
    在.文件里定義一個(gè)宏:C


    image.png

使用命令:clang -E main.m >> main2.m,生成main2.m文件
查看main2.m:大部分是stdio庫的代碼价说,定位到main函數(shù)里,發(fā)現(xiàn)
C變成了50了

image.png

得知扮叨,
預(yù)處理:????????????????????????????????????????完成2個(gè)步驟彻磁,

  1. 導(dǎo)入頭文件 2.替換宏

還有一個(gè)定義類型的叫做typedef,這里我們把 int替換成wl_INT64,試試是否會(huì)還原

image.png

預(yù)處理結(jié)束:


image.png

發(fā)現(xiàn)tydef并沒有被還原

由此我們可以根據(jù)預(yù)處理結(jié)果屡限,做一些安全管理方面的混淆措施

使用define,將重要方法名稱或者類進(jìn)行替換瞧省。比如用#define BUY XXXDemo
代碼中使用宏BUY鞍匾,被hank時(shí),實(shí)際代碼是XXXDemo构拳,不易被發(fā)現(xiàn)梁棠。
且#define的真實(shí)內(nèi)容,不應(yīng)該寫成亂碼凫海,會(huì)讓人有此地?zé)o銀三百兩的感覺男娄,最好弄成系統(tǒng)類似名稱或其他不經(jīng)意的名稱模闲。才會(huì)被忽視,安全級(jí)別會(huì)更高 啰脚。

  • 編譯
    【1】詞法分析
    使用clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
image.png

這些將代碼拆分成一個(gè)個(gè)Token橄浓。標(biāo)注了位置是第幾行的第幾個(gè)字符開始的。

【2】語法分析
是驗(yàn)證語法是否正確:

  • 在詞法分析的基礎(chǔ)上谍倦,將單詞序列組合成各類語法短語泪勒,如“程序”,“語句”叼旋,“表達(dá)式”等沦辙,然后將所有節(jié)點(diǎn)組成抽象語法樹(Abstract Syntax Tree油讯,AST)。 語法分析程序判斷源程序在結(jié)構(gòu)上是否正確沈跨。
    使用clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
image.png
  • 可以看到語法樹饿凛。每一個(gè)操作都生成一個(gè)變量软驰,作用域、數(shù)據(jù)類型纠吴、運(yùn)算方式都在語法樹體現(xiàn)出來贰镣。
  • 語法樹一次只能處理一次計(jì)算兩次運(yùn)算碑隆,就得多分一層蹬音。
  • 語法分析著淆,就是在生成語法樹時(shí)完成檢測(cè)的
    ?????????????????????????????? 如果頭文件找不到拴疤,可以指定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)會(huì)將語法樹自頂向下遍歷逐步翻譯成LLVM的IR。通過下面命令生成.ll文本文件罚随,查看IR代碼:
    clang -S -fobjc-arc -emit-llvm main.m

    image.png

  • 代碼在這一階段進(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ù)據(jù)
ret 返回

  • IR的優(yōu)化
    llvm的優(yōu)化級(jí)別分別是 ???????????????? -O0 -O1 -O2 -O3 -Os(????????????????????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

補(bǔ):日常開發(fā)中以蕴,我們引入第三方庫,有時(shí)會(huì)提示不支持bitcode赡磅,可以通過一焚廊、將源碼編譯一下习劫,二、工程設(shè)置不支持.bitcode即可

  • 生成匯編代碼
    我們通過最終生成的.bc或者.ll代生成匯編代碼
    clang -S -fobjc-arc main.bc -o main.s
    clang -S -fobjc-arc main.ll -o main.s

    image.png

    匯編代碼也可以進(jìn)行優(yōu)化clang -Os -S -fobjc-arc main.m -o main.s

  • 生成目標(biāo)文件(匯編器)
    目標(biāo)文件的生成,是匯編器以匯編代碼作為輸入,將匯編代碼轉(zhuǎn)換為機(jī)器代碼卧檐,最后輸出目標(biāo)文件(object file)
    clang -fmodules -c main.s -o main.o

    image.png

    通過nm命令霉囚,查看下main.o中的符號(hào):nm -nm main.o
    image.png

_printf 是一個(gè)是undefined external的
undefined表示在當(dāng)前文件暫時(shí)找不到符號(hào)_printf
external表示這個(gè)符號(hào)是外部可以訪問的佛嬉。
以上打印結(jié)果表示是因?yàn)閜rintf闸天、PoolPop、PoolPush函數(shù)是來自于其他庫湾揽,所以找不到笼吟,需要鏈接其他目標(biāo)文件

  • 生成可執(zhí)行文件(鏈接)??????????????????????
    連接器把編譯產(chǎn)生的.o文件和(.dylib.a)文件贷帮,生成一個(gè)mach-o文件
    clang main.o -o main
    查看鏈接后的符號(hào)
    nm -nm main

四、重新編輯Clang插件
由于國(guó)內(nèi)網(wǎng)絡(luò)限制民晒,我們需要借助鏡像下載LLVM源碼
https://mirror.tuna.tsinghua.edu.cn/help/llvm/

  • 在llvm的tools目錄下下載Clang

cd llvm/tools
git clone https://mirrors.tuna.tsinghua.edu.cn/git/llvm/clang.git

  • 在LLVM的projects目錄下下載compiler-rt??libcxx锄禽、??libcxxabi
  • 在clang的tools下安裝extra工具
  • llvm編譯沃但,最新的只支持cmake來編譯,所以需要安裝cmake
  • 通過brew安裝cmake
    brew install cmake

通過Xcode編譯llvm

  • cmake編譯成Xcode項(xiàng)目

一頓猛如虎的操作后垂攘,電腦沒燒壞的情況下淤刃,就編譯成功了,然后創(chuàng)建插件仪芒,請(qǐng)聽下回分解~??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掂名,一起剝皮案震驚了整個(gè)濱河市哟沫,隨后出現(xiàn)的幾起案子嗜诀,更是在濱河造成了極大的恐慌,老刑警劉巖发皿,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拂蝎,死亡現(xiàn)場(chǎng)離奇詭異温自,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)松捉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門隘世,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸠踪,“玉大人,你說我怎么就攤上這事蔓钟÷鸭” “怎么了键俱?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵编振,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我臀玄,道長(zhǎng),這世上最難降的妖魔是什么荣恐? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任叠穆,我火速辦了婚禮臼膏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嚷硫。我一直安慰自己夺溢,他們只是感情好风响,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布状勤。 她就那樣靜靜地躺著,像睡著了一般密似。 火紅的嫁衣襯著肌膚如雪葫盼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音孩灯,去河邊找鬼峰档。 笑死寨昙,一個(gè)胖子當(dāng)著我的面吹牛掀亩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尸红,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼特石!你這毒婦竟也來了鳖链?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎灌侣,沒想到半個(gè)月后侧啼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痊乾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年皮壁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哪审。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛾魄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出湿滓,到底是詐尸還是另有隱情滴须,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布茉稠,位于F島的核電站,受9級(jí)特大地震影響而线,放射性物質(zhì)發(fā)生泄漏铭污。R本人自食惡果不足惜恋日,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘹狞。 院中可真熱鬧岂膳,春花似錦、人聲如沸磅网。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涧偷。三九已至簸喂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間燎潮,已是汗流浹背喻鳄。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留确封,地道東北人除呵。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爪喘,于是被迫代替她去往敵國(guó)和親颜曾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 前言 ? 計(jì)算機(jī)是只能直接理解機(jī)器語言秉剑,而不能直接理解高級(jí)語言的泛豪,所以計(jì)算機(jī)要執(zhí)行高級(jí)語言編寫的程序,就必須要把高...
    xxxxxxxx_123閱讀 840評(píng)論 4 0
  • 一秃症、編譯器概述 編譯器就是說將高級(jí)語言 翻譯 為低級(jí)語言的程序候址。 二、LLVM概述 ??LLVM 是 構(gòu)架編譯器 ...
    腳踏實(shí)地的小C閱讀 526評(píng)論 0 0
  • 目錄 傳統(tǒng)編譯器設(shè)計(jì) 輸入源代碼(Obj-C, Swift, ...) → 編譯器處理 → 輸出機(jī)器碼(01010...
    小瞎_MarkDash閱讀 1,226評(píng)論 0 2
  • 前言 2000年种柑,伊利諾伊大學(xué)厄巴納-香檳分校(University of Illinois at Urbana-...
    星光社的戴銘閱讀 15,861評(píng)論 8 180
  • 本文將簡(jiǎn)單介紹 Clang LLVM 相關(guān)的知識(shí)岗仑,然后介紹一下代碼是如何一步步的編譯運(yùn)行的,以及可以利用 clan...
    z4ywzrq閱讀 2,552評(píng)論 0 0