編譯過程
傳統(tǒng)編譯過程一般分為以下步驟盗似。
源代碼(source code)→ 預(yù)處理器(preprocessor)→ 編譯器(compiler)→ 匯編程序(assembler)→ 目標(biāo)代碼(object code)→ 鏈接器(linker)→ 可執(zhí)行文件(executables)
其中預(yù)處理主要工作是宏定義的替換和頭文件的引入
編譯器
簡單而言六敬,編譯器的設(shè)計一般分為三部分
傳統(tǒng)編譯器(compiler)的設(shè)計一般如下圖所示
LLVM編譯器設(shè)計如圖所示
- 前端 Frontend:前端的主要工作是解析源代碼地粪, 詞法分析、語法分析幕帆、語義分析眯搭、檢查源代碼是否存在錯誤错负,然后構(gòu)建抽象語法樹(Abstract Syntax Tree AST)。
- 優(yōu)化器 Optimizer:負(fù)責(zé)優(yōu)化代碼操禀,例如消除冗余褂策。
- 后端 Backend:將代碼映射到目標(biāo)指令集,生成機(jī)器代碼。
LLVM
底層虛擬機(jī)(Low Level Virtual Machine)斤寂,LLVM是一套編譯器基礎(chǔ)設(shè)施項目耿焊,以C++寫成,包含一系列模塊化的編譯器組件和工具鏈扬蕊,用來開發(fā)編譯器前端和后端搀别。優(yōu)化各種語言寫的程序在編譯過程中環(huán)節(jié),如編譯時期尾抑、鏈接時期歇父、運行時期以及閑置時期。
LLVM前端
Clang是LLVM編譯器工具集的前端(front-end)再愈,屬于LLVM項目中的一個子項目榜苫,它是基于LLVM架構(gòu)圖的輕量級編譯器,Clang的現(xiàn)在已經(jīng)取代GCC翎冲,負(fù)責(zé)C垂睬、C++、OC語言的編譯抗悍。Clang主要工作是輸出代碼對應(yīng)的抽象語法樹(Abstract Syntax Tree, AST)驹饺,并將代碼編譯成LLVM Bitcode。接著在后端(back-end)使用LLVM編譯成平臺相關(guān)的機(jī)器語言缴渊。
LLVM中間端
LLVM的核心是中間端表達(dá)式(Intermediate Representation赏壹,IR),一種類似匯編的底層語言衔沼。
LLVM后端
LLVM后端的主要工作是將LLVM中間端表達(dá)式(IR)轉(zhuǎn)換成特定目標(biāo)機(jī)器代碼(object code)蝌借,機(jī)器代碼一般由機(jī)器代碼或接近于機(jī)器語言的代碼組成。即存放目標(biāo)代碼的計算機(jī)文件指蚁,它常被稱作二進(jìn)制文件(binaries)菩佑。目前LLVM支持輸出多種后端指令集,包括X86凝化、PowerPC稍坯、ARM以及SPARC等。目標(biāo)文件包含著機(jī)器代碼(可直接被CPU執(zhí)行)以及代碼在運行時使用的數(shù)據(jù)缘圈,如重定位信息劣光,如用于鏈接或調(diào)試的程序符號(變量和函數(shù)的名字),此外還包括其他調(diào)試信息糟把。目標(biāo)文件是從源代碼文件產(chǎn)生程序文件這一過程的中間產(chǎn)物绢涡。
LLVM鏈接器
LLD是LLVM項目中的鏈接器,替換GNU系統(tǒng)鏈接器遣疯。LLD把目標(biāo)文件(.o文件和 .dyld .a)鏈接在一起來生成可執(zhí)行文件或庫文件(mach-o文件)雄可。
Mach-O文件格式
Mach-O 是 iOS 可執(zhí)行文件的格式凿傅,典型的 Mach-O 是主二進(jìn)制和動態(tài)庫。Mach-O 可以分為三部分:
- Header
- Load Commands
- Data
Header 的最開始是 Magic Number数苫,表示這是一個 Mach-O 文件聪舒,除此之外還包含一些 Flags,這些 flags 會影響 Mach-O 的解析虐急。
Load Commands 存儲 Mach-O 的布局信息箱残,比如 Segment command 和 Data 中的 Segment/Section 是一一對應(yīng)的。除了布局信息之外止吁,還包含了依賴的動態(tài)庫等啟動 App 需要的信息被辑。
Data 部分包含了實際的代碼和數(shù)據(jù),Data 被分割成很多個 Segment敬惦,每個 Segment 又被劃分成很多個 Section盼理,分別存放不同類型的數(shù)據(jù)。
標(biāo)準(zhǔn)的三個 Segment 是 TEXT俄删,DATA宏怔,LINKEDIT,也支持自定義:
- TEXT畴椰,代碼段臊诊,只讀可執(zhí)行,存儲函數(shù)的二進(jìn)制代碼(__text)斜脂,常量字符串(__cstring)妨猩,Objective C 的類/方法名等信息
- DATA,數(shù)據(jù)段秽褒,讀寫,存儲 Objective C 的字符串(__cfstring)威兜,以及運行時的元數(shù)據(jù):class/protocol/method…
- LINKEDIT销斟,啟動 App 需要的信息,如 bind & rebase 的地址椒舵,代碼簽名蚂踊,符號表…
iTunes Connect 會對上傳 Mach-O 的 TEXT 段進(jìn)行加密,防止 IPA 下載下來就直接可以看到代碼笔宿。這也就是為什么逆向里會有個概念叫做“砸殼”犁钟,砸的就是這一層 TEXT 段加密。iOS 13 對這個過程進(jìn)行了優(yōu)化泼橘,在博文中的page fault過程中涝动,需要讀取Page In 的時候不需要解密了。
參考文章
http://www.aosabook.org/en/llvm.html
抖音品質(zhì)建設(shè) - iOS啟動優(yōu)化《原理篇》