主頁 > 移動端開發 > iOS啟動優化 —— LLVM編譯流程 & Clang插件開發

iOS啟動優化 —— LLVM編譯流程 & Clang插件開發

2021-09-01 13:08:25 移動端開發

1. LLVM

1.1 LLVM概述

LLVM是架構編譯器的框架系統,以C++撰寫而成,用于優化任意程式語言撰寫的程式的編譯時間(compile-time)鏈接時間(link-time)運行時間(run-time)以及空閑時間(idle-time),對開發者保持開放,并兼容已有腳本,目前LLVM已經被蘋果IOS開發工具,Xilinx Vivado, Facebook,Google等各大公司采用,

1.2 傳統編譯器設計

原始碼 Source Code + 前端 Frontend + 優化器 Optimizer + 后端 Backend(代碼生成器 CodeGenerator)+ 機器碼 Machine Code,如下圖所示

  • 前端Frontend:負責決議源代碼,它會進行:詞法分析語法分析語意分析,檢查源代碼是否存在錯誤,然后構建針對語言的抽象語法樹AST:Abstract Syntax Tree,LLVM 的前端還會生成中間代碼(intermediate representation,簡稱IR)

  • 優化器 Optimizer:優化器負責進行各種優化,改善代碼的運行時間,例如消除冗余計算等;

  • 后端 Backend(代碼生成器 Code Generator):將代碼映射到目標指令集,生成機器代碼,并且進行機器代碼相關的代碼優化;

1.3 ios的編譯器架構

OC、C、C++使用的編譯器前端是ClangSwift是swift,后端都是LLVM,如下圖所示

1.4 LLVM的設計

LLVM設計的最重要方面是,使用通用的代碼表示形式(IR),它是用來在編譯器中表示代碼的形式,所有LLVM可以為任何編程語言獨立撰寫前端,并且可以為任意硬體架構獨立撰寫后端,做到了前后端分離如下所示

傳統的編譯器,前端,優化器和后端是連在一起的,是一個專案,但是在llvm中,前端和后端分開了,兩者中間有一個通用的中間層,也就是IR,前端決議源代碼,然后詞法分析語法分析語意分析AST等作業完成之后,生成IR輸出給優化器,優化器負責優化IR代碼,然后后端接受IR代碼后根據需要適配的設備生成X86、ARM64等,所以,當出現一個新設備,只需要研發一個新設備的后端,出現一個高級語言,就研發高級語言的前端,這樣就能支持所有的語言和設備,

1.5 Clang

clangLLVM專案中的一個子專案,它是基于LLVM架構圖的輕量級編譯器,誕生之初是為了替代GCC,提供更快的編譯速度,它是負責C、C++、OC語言的編譯器,屬于整個LLVM架構中的 編譯器前端,對于開發者來說,研究Clang可以給我們帶來很多好處

2. 編譯流程

可以通過以下命令列印原始碼的編譯階段:

clang -ccc-print-phases main.m

這里新建一個后通過命令列印原始碼的編譯階段:

  • 0 - 輸入檔案:找到源檔案
  • 1 - 預處理階段:這個程序處理包括宏的替換,頭檔案的匯入
  • 2 - 編譯階段:進行詞法分析、語法分析、檢測語法是否正確,最終生成IR
  • 3 - 后端:這里LLVM會通過一個一個的pass去優化,每個pass做一些事情,最終生成匯編代碼
  • 4 - 匯編代碼生成目標檔案
  • 5 - 鏈接:鏈接需要的動態庫和靜態庫,生成可執行檔案
  • 6 - 系結:通過不同的架構,生成對應架構的可執行檔案

在main.m中輸入一些代碼,

然后通過 指令clang -E main.m >> main1.m生成預處理之后的檔案,

開頭是一些宏展開和.h檔案的展開,

然后最后看到main函式,這里成C沒有了,變成了30.

所以我們得出:

  • typedef不是預處理指令,也就是說:typedef可以給資料型別取別名,但是在預處理階段不會被替換掉
  • define則在預處理階段會被替換,所以經常被是用來進行代碼混淆,目的是為了app安全

3. 編譯階段

編譯階段會進行詞法分析語法分析檢測語法是否正確,最終生成IR,

3.1 詞法分析

預處理完成后就會進行詞法分析,這里會把代碼切成一個個Token,比如大小括號等于號還有字串等, 通過下列指令來查看詞法分析

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

詞法分析結果:

3.2 語法分析

詞法分析完成后就是語法分析,它的任務是驗證語法是否正確,在詞法分析的基礎上將單詞序列組合成各類詞法短語,如程式陳述句運算式 等等,然后將所有節點組成抽象語法樹(Abstract Syntax Tree,AST),語法分析程式判斷程式在結構上是否正確,

通過下列指令來查看語法分析

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

得到下面的結果(這里面的地址是虛擬地址,還沒開辟記憶體,可以看作是檔案的偏移地址):

  • FunctionDecl :函式方法宣告,
  • ParmVarDecl: 引數宣告,
  • CompoundStmt:復合陳述句,
  • CallExpr:函式呼叫,
  • BinaryOperator: 運算子,
  • ImplicitCastExpr:函式指標,
  • DeclRefExpr:函式型別,

3.3 生成中間代碼IR

完成以上步驟后,就開始生成中間代碼IR了,代碼生成器(Code Generation)會將語法樹自頂向下遍歷逐步翻譯成LLVM IR,

簡化一下代碼:

然后通過下列指令來生成 .ll 的文本檔案,查看IR代碼,

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

生成IR代碼如下(這一步會進行語法檢查):

  • @:全域標識
  • %:區域標識
  • alloca: 開辟空間
  • align: 記憶體對齊
  • i32: 32bit,4個位元組
  • store: 寫入記憶體
  • load: 讀取資料
  • call: 呼叫函式
  • ret: 回傳

上面的IR代碼是沒有經過優化的,所以會比較長, LLVM的優化級別分別是: -O0 , -O1 , -O2 , -O3 , -Os , 可以在xcode里面 target -> Build Settings -> optimization Level 設定優化等級,

輸入下列指令來生成優化后的IR代碼

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

下面是優化后的IR代碼,可以明顯看出來代碼少了很多,優化等級并不是越高越好的,一般情況下,debug模式下是不進行優化的,而在release模式下是-Os 優化等級

3.4 bitCode

xcode7以后開啟bitcode,蘋果會做進一步優化,生成.bc的中間代碼,我們通過優化后的IR代碼生成.bc代碼,Bitcode的目的是根據不同的CPU架構,蘋果能夠在APPStore直接下載不同的架構的包

輸入下列指令來生成bc代碼,

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

4. 生成匯編代碼

到了這一步,這里就到了backend,這里LLVM會通過一個一個的pass去優化,每個pass做一些事情,最終生成匯編代碼,

我們通過生成的.bc或者.ll代碼生成匯編代碼,

 clang -S -fobjc-arc main.bc -o main.s
 clang -S -fobjc-arc main.ll -o main.s

這里分別通過main.llmain.bcmain.m來生成匯編之后進行對比,

main.bc生成的匯編代碼:

main.ll生成的匯編代碼:

main.m生成的匯編代碼:

這里發現通過main.bc 和 main.ll 生成的匯編代碼都是54行,說明并沒有額外進行代碼優化,main.m是沒有經過優化的原始碼,轉化為匯編后則多了幾行代碼,那么這里的代碼是否還能進行優化呢?試一下, 輸入以下代碼

clang -Os -S -fobjc-arc main.bc -o main3.s

這是指令運行后得到的代碼,發現比之前的又少了幾行,這就說明:當選定了優化等級了之后,在不同的節點上,還能進行優化,

5. 生成目標檔案(匯編器)

目標檔案的生成,是匯編器以匯編代碼作為插入,將匯編代碼轉換為機器代碼,最后輸出目標檔案(object file),

通過以下指令來生產.o檔案

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

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

$xcrun nm -nm main.o

指令執行后發現輸出下面的結果:

  • _printf函式是一個是undefinedexternal
  • undefined表示在當前檔案暫時找不到符號_printf
  • external表示這個符號是外部可以訪問

這里為什么undefined了呢?因為這里呼叫了外部的方法,這個時候就需要鏈接了,

6. 生成可執行檔案(鏈接)

鏈接主要是鏈接需要的動態庫和靜態庫,生成可執行檔案,

連接器把編譯生成的.o檔案和 .dyld .a檔案鏈接,生成一個mach-o檔案

clang main.o -o main

查看鏈接之后的符號

$xcrun nm -nm main

指令執行后得到下面的結果:

這里看到有兩個undefined,一個是_printf,一個是dyld_stub_binder,但是后面都有(from libSystem),這里的dyld_stub_binder也是一個外部函式,在dyld里面,當mach-o 進入到記憶體之后,外部符號就會和binder進行系結,這個程序是dyld強制系結的,這里就是去系結_printf, 鏈接就是要知道內部的符號是在外面的哪個庫里面,系結就是將外面的函式的地址和內部的符號進行系結,鏈接編譯期系結執行期,所以只要鏈接就一定有一個外部函式也就是dyld_stub_binder,

7. clang 插件

7.1 LLVM下載

	由于國內網路限制,需要借助鏡像下載llvm的原始碼鏈接: [link](https://mirror.tuna.tsinghua.edu.cn/help/llvm/).
復制代碼

下載LLVM專案

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

在LLVM的tool目錄下下載Clang

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

在LLVM的projects目錄下下載compiler-rt、libcxx、libcxxabi

cd ../projects
git clone https://mirrors.tuna.tsinghua.edu.cn/git/llvm/compiler-rt.g it
git clone https://mirrors.tuna.tsinghua.edu.cn/git/llvm/libcxx.git git clone 
https://mirrors.tuna.tsinghua.edu.cn/git/llvm/libcxxabi.git

在Clang的tools下安裝extra工具

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

7.2 LLVM 編譯

由于最新的LLVM只支持cmake來編譯,所以需要安裝cmake

查看brew是否安裝cmake,如果已經安裝,則跳過下面步驟

brew list

通過brew安裝cmake

brew install cmake

7.3 編譯LLVM

通過xcode編譯LLVM

  • cmake編譯成Xcode專案
mkdir build_xcode
cd build_xcode
cmake -G Xcode ../llvm
  • 使用xcode編譯Clang

選擇手動創建schemes

編譯(CMD + B),選擇ALL_BUILD Secheme進行編譯,預計1+小時,

通過ninja編譯LLVM

使用ninja進行編譯則還需要安裝ninja,使用以下命令安裝ninja

brew install ninja

在LLVM原始碼根目錄下新建一個build_ninja目錄,最侄訓在build_ninja目錄下生成``build.ninja`

在LLVM原始碼根目錄下新建llvm_release目錄,最終編譯檔案會在llvm_release檔案夾路徑下

cd llvm_build
//注意DCMAKE_INSTALL_PREFIX后面不能有空格
cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX= 安裝路徑(本機為/ Users/xxx/xxx/LLVM/llvm_release)

依次執行編譯,安裝指令

ninja
ninja install

7.4 創建插件

在/llvm/tools/clang/tools下新建插件LSPlugin

在/llvm/tools/clang/tools目錄下的CMakeLists.txt檔案,新增add_clang_subdirectory(LSPlugin),

在LSPlugin目錄下新建 LSPlugin.cpp 和CMakeLists.txt,并在CMakeLists.txt中加上以下代碼

add_llvm_library( HKPlugin MODULE BUILDTREE_ONLY
  LSPlugin.cpp
)

接下來利用cmake重新生成Xcode專案,在build_xcode目錄下執行以下命令

cmake -G Xcode ../llvm

最后可以在LLVM的xcode專案中可以看到Loadable modules目錄下由自定義的LSPlugin目錄了,然后可以在里面撰寫插件代碼了,

面試基礎

iOS面試基礎知識 (一)

iOS面試基礎知識 (二)

iOS面試基礎知識 (三)

iOS面試基礎知識 (四)

iOS面試基礎知識 (五)

知識詳解

iOS面試要點之GCD面試要點

iOS面試要點之多執行緒面試要點

iOS面試要點之block面試要點

iOS面試要點之Runtime面試要點

iOS面試要點之RunLoop面試要點

iOS面試要點之記憶體管理面試要點

iOS面試要點之MVC、MVVM面試要點

iOS面試要點之網路性能優化要點

iOS面試要點之網路編程面試要點

iOS面試要點之KVC&KVO面試要點

iOS面試要點之資料存盤面試要點

iOS面試要點之混編技術面試要點

iOS面試要點之設計模式面試要點

iOS面試要點之UI面試要點

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/296463.html

標籤:其他

上一篇:百度地圖開發-繪制點線提示框 07

下一篇:華為動態標簽管理如何助力廣告營銷

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more