iOS底層探索(二) - 寫給小白看的Clang編譯過程原理

iOS底層探索(一) - 從零開始認識Clang與LLVM

寫在前面

編譯器是屬于底層知識,在日常開發中少有涉及,但在我的印象中,越接近底層是越需要編程基本功,也是越復雜的。但要想提升技術卻始終繞不開要對底層原理的探究,很多資料都是直接拋出一堆函數概念和一頓操作,基礎一般的小伙伴看了表示一臉懵逼。在此結合我自己的理解進行優化總結一下。畢竟知識水平有限,有問題或總結不妥的地方歡迎指出,多多學習,非常感謝!2018.2

入門起步

  • 經過上一篇對編譯器的基本介紹,相信大家對Clang都有一個基本的認識了,通俗來說是一個編譯器的前端,負責分析源代碼(就是我們使用的C/OC/C++等)。

Clang的編譯過程

1.預處理

  • 預處理顧名思義是預先處理,那預處理都做了哪些事情呢?內容如下。

  • (1) import 頭文件替換

    • 面向對象編程的思維下,我們寫代碼會經常用到其他類的屬性\方法等,我們只需要導入頭文件就可以用了,如:

      #import <Foundation/Foundation.h> 
      // 這里將會在預處理時會把 Foundation.h 文件的內容拷貝過來并替換
      復制代碼
    • 基于這個原理,這里引出了一個小問題,如果 ClassA.h 文件引用了 ClassB.h ,并且 ClassB.h 也引用了 ClassA.h ,這里是不是就會互相循環引入了?

      • 解決辦法是在頭文件中使用
      @class ClassA;
      復制代碼
      • 代替
      #import "ClassA.h"
      復制代碼
      • 這么寫意思是聲明 ClassA 是一個類,這樣你就可以使用ClassA做類名了,如果需要使用 ClassA 的方法屬性等可以在 .m 實現文件中再通過 import MyClass.h 的方式使用,這種方法不但可以解決互相引入的問題還可以優化編譯速度。
  • (2) macro 宏展開

    • 無參宏: 如:

      #define DATA_TYPE_NUM @"number"
      復制代碼

      在此宏定義作用域內,輸入了 DATA_TYPE_NUM,在預處理過程中 DATA_TYPE_NUM 都會被替換成 @"number"。

    • 帶參宏: 帶參數的宏 如:

      #define CYXColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
      復制代碼
  • (3) 處理其他的預編譯指令(其實預編譯過程也是出了預編譯指令的過程)

    條件編譯語句也是在預處理階段完成,并且條件編譯只允許編譯源程序中滿足條件的程序段,使生成的目標程序較短,從而減少了內存的開銷并提高了程序的效率,如以下代碼就只會保留一個return語句:

    #if DEBUG        return YES;
    #elsereturn NO;
    #endif
    復制代碼
  • (4) 總結:

    • 簡單來說,“#”這個符號是編譯器預處理的標志, 以下是一些常用的預處理指令參考
    預處理指令用法解析
    #undef取消已定義的宏
    #if如果給定條件為真,則編譯以下代碼
    #ifdef如果宏已經定義,則編譯以下代碼
    #ifndef如果宏沒有定義,則編譯以下代碼
    #elif如果前面的#if給定條件不為真,當前條件為真,則編譯以下代碼
    #endif結束一個#if……#else條件編譯塊
*PS:還需要了解更多關于預編譯的內容,還請自行百度*
[圖片上傳失敗...(image-cf6f6f-1531632712782)][圖片上傳失敗...(image-fd9112-1531632712782)]`$clang -E main.m`
復制代碼

2. Lexical Analysis - 詞法分析(輸出token流)

  • 預處理完成了以后,開始詞法分析。詞法分析其實是編譯器開始工作真正意義上的第一個步驟,其所做的工作主要為將輸入的代碼轉換為一系列符合特定語言的詞法單元,這些詞法單元類型包括了關鍵字,操作符,變量等等。舉個例子:

Objective-C語言包含了關鍵字if、else、new等,那么在詞法分析步驟時,遇到i與f或n與e與w組合在一起的時候,需要將這幾個字母組合為關鍵字if或new這個詞法單元。

  • 詞法分析,只需要將源代碼以字符文本的形式轉化成Token流的形式,不涉及交驗語義,不需要遞歸,是線性的。

    什么是token流呢?可以這么理解:就是有"類型",有"值"的一些小單元。

  • 再舉個例子:

    比如一個運算表達式:(28 + 78) * 2 這里面只需要解析出(是一個開括號,28 是數字整形,+ 是一個運算符號即可。

編譯指令: $clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m

3.Semantic Analysis - 語法分析(輸出(AST)抽象語法樹)

編譯指令:$clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

  • 語法分析的最終產物是輸出抽象語法樹

  • 語法分析,在Clang中由Parser和Sema兩個模塊配合完成

  • 交驗語法是否正確

  • 根據當前語言的語法,生成語意節點,并將所有節點組合成抽象語法樹(AST)

  • 這一步跟源碼等價,可以反寫出源碼

  • Static Analysis 靜態分析

    • 通過語法樹進行代碼靜態分析,找出非語法性錯誤
    • 模擬代碼執行路徑,分析出control-flow graph(CFG) 【MRC時代會分析出引用計數的錯誤】
    • 預置了常用Checker(檢查器)

未完待續 ...

這是上篇,為保證博客質量與閱讀體驗(個人感覺一次閱讀過多文字有點影響閱讀體驗),先分享已完成的上半部分,下篇將繼續介紹Clang編譯過程中的剩下環節,歡迎持續關注,感謝理解與支持!2018.2

預告:下篇將繼續介紹Clang與LLVM以下環節的相關知識。

下面是一些關鍵詞,有興趣的朋友先自行谷歌學習吧,下篇等我有閑情的時候再更新了,我也不知道什么時候。2018.7.15

4. CodeGen - (Intermediate Representation,簡稱IR)IR中間代碼生成

  • CodeGen 負責將語法樹叢頂至下遍歷,翻譯成LLVM IR
  • LLVM IR 是Frontend的輸出,也是LLVM Backend的輸入,前后端的橋接語言 (Swift也是轉成這個)
  • 與 Objective-C Runtime 橋接
    • Class/Meta Class/Protocol/Category內存結構生成,并存放在指定section中(如Class:_DATA, _objc_classrefs)
    • Method/lvar/Property內存結構生成
    • 組成method_list/ivar_list/property_list并填入Class
    • Non-Fragile ABI:為每個Ivar合成OBJC_IVAR_$_偏移值常量
    • 存取Ivar的語句(ivar = 123; int a = ivar;)轉寫成base + OBJC_IVAR$_的形式
    • 將語法樹中的ObjcMessageExpr翻譯成相應版本的objc_msgSend,對super關鍵字的調用翻譯成objc_msgSendSuper
    • 根據修飾符strong/weak/copy/atomic合成@property 自動實現的 setter/getter
    • 處理@synthesize
    • 生成block_layout的數據結構
    • 變量的capture(__block/__weak)
    • 生成_block_invoke函數
    • ARC:分析對象引用關系,將objc_storeStrong/objc_storeWeak等ARC代碼插入
    • 將ObjCAutoreleasePoolStmt轉譯成objc_autoreleasePoolPush/Pop
    • 實現自動調用[super dealloc]
    • 為每個擁有ivar的Class合成.cxx_destructor方法來自動釋放類的成員變量,代替MRC時代的“self.xxx = nil”

5. Optimize - 優化IR

  • 遞歸優化成偽遞歸

6. LLVM Bitcode - 生成字節碼

7. Assemble - 生成Target相關匯編

  • Assemble - 生成Target相關Object(Mach-O)

8. Link生成Executable

參考文檔

https://zh.wikipedia.org/wiki/C%E9%A2%84%E5%A4%84%E7%90%86%E5%99%A8 https://llvm.org/docs/tutorial/LangImpl2.html https://www.objc.io/issues/6-build-tools/compiler/

轉載于:https://juejin.im/post/5b4af8b0e51d45199060fdf8

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/277657.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/277657.shtml
英文地址,請注明出處:http://en.pswp.cn/news/277657.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

四、構建Node Web程序

---恢復內容開始--- 一、HTTP 服務器的基礎知識 1、Node如何向開發者呈現HTTP請求 2、一個用“Hello World”做響應的HTTP服務器 它用了默 認的狀態碼200&#xff08;表明成功&#xff09;和默認的響應頭 3、讀取請求頭及設定響應頭 Node提供了幾個修改HTTP響應頭的方法&#x…

datagrid 什么時候結束編輯_2020年中考結束后,什么時候出分?什么時候報志愿?...

導語7月19日下午16:00&#xff0c;2020年北京中考正式落下帷幕。考試結束后&#xff0c;很多家長和考生都會長舒一口氣&#xff0c;但北京中考在線團隊提醒你&#xff0c;現在還不是放松的時刻&#xff0c;中考結束后&#xff0c;還有成績查詢和填報志愿等重要事件等著你。那么…

Unity3D學習筆記之七創建自己的游戲場景

到現在為止我們已經擁有了比較完備的Prefab&#xff0c;已經可以創建宏大的游戲場景&#xff0c;并以第一人稱視角在場景中漫游了。這里給大家做個小的示范&#xff0c;建一個小場景大家在創建場景的時候需要自由發揮&#xff0c;做個盡量大的場景出來。這一系列教程以及素材均…

excel if in函數_【Excel函數】Small+Index+IF 一對N返回

通常情況下&#xff0c;Vlookup和lookup函數只能返回滿足條件的第一個&#xff0c;剩余的都不會返回。 這也是其函數的一個弊端之一。 若是按照條件&#xff0c;返回所有滿足條件的數據&#xff08;1->N&#xff09;的&#xff0c;可是適用組合函數。 Index返回位置&#xf…

Unity3D學習筆記之八為場景添加細節(一)

這一系列教程以及素材均參考自人人素材翻譯組出品的翻譯教程《Unity游戲引擎的基礎入門視頻教程》&#xff0c;下載鏈接附在第二篇學習筆記中。我花了30分鐘做了一個中等大小的迷宮場景&#xff0c;不知道大家自己發揮&#xff0c;做的場景大小如何。在完成場景之后&#xff0c…

mysql數據庫表的管理(增刪改)

表字段管理1. 添加到末尾alter table 表名 add 字段名 數據類型;2 添加到開頭alter table 表名 add 數據類型 first;3. 添加到指定位置alter table 表名 add 新字段名 數據類型 after 原有字段名&#xff1b;4. 刪除字段alter table 表名 drop 字段名;5. 修改數據類型alter ta…

哪個app最費電_微波爐和烤箱,買哪個劃算?

微波爐和烤箱不能說買哪個劃算&#xff0c;而是看哪個更適合&#xff1f;我家微波爐和烤箱兩個都有&#xff0c;所以這個問題我來回答一下。雖然外形上看起來&#xff0c;微波爐和烤箱似乎沒有多大的區別&#xff0c;從功能上看&#xff0c;它們也都是加熱&#xff0c;但它們側…

MATLAB數值計算與符號運算

符號計算 存放的是精確數據&#xff0c;耗存儲空間 &#xff0c;運行速度慢&#xff0c;但結果精度高&#xff1b; 數值計算則是以一定精度來計算的&#xff0c;計算結果有誤差&#xff0c;但是運行速度快。轉載于:https://www.cnblogs.com/shawnchou/p/10927680.html

Unity3D學習筆記之九為場景添加細節(二)

上節為場景中添加了第一塊帶有碰撞器的石頭&#xff0c;本節我們來利用Prefab&#xff0c;將場景細節都添加進去&#xff0c;并且做的更完善。這一系列教程以及素材均參考自人人素材翻譯組出品的翻譯教程《Unity游戲引擎的基礎入門視頻教程》&#xff0c;下載鏈接附在第二篇學習…

vux Cell組件

Cell 組件一 <style lang"scss">.cell {padding-top: 15px;padding-bottom: 15px;color: #333;img {display: block;margin-right: 15px;}} </style><template><Group><cell class"cell" title"錢包" :border-intent…

wifi名稱可以有空格嗎_收購公司后可以變更公司名稱嗎,變更公司名稱和股權如何處理?...

【點擊文末小程序&#xff0c;免費咨詢法律問題】公司收購是指二手設備收購&#xff0c;指向目標公司的二手設備&#xff0c;廢舊物資&#xff0c;進而獲取目標公司的全部或部分業務&#xff0c;取得對拆除的控制權。那么&#xff0c;收購公司后可以變更公司名稱嗎&#xff0c;…

震驚的網站,都是干貨

分享15個鮮為人知的的小眾網站&#xff0c;每一個可以讓你打開新世界的大門&#xff0c;讓你震驚。 1&#xff1a;仿知網 https://www.cn-ki.net/ 仿知網是一個完全可以代替知網的精品網站&#xff1b;是一個非常強大的論文搜索網站。 首先這個網站的論文檢索結果和知網的搜索結…

Kinect開發筆記之二Kinect for Windows 2.0新特性

這是本博客的第一篇翻譯文檔&#xff0c;筆者已經苦逼的竭盡全力的在翻譯了&#xff0c;但無奈英語水平也是很有限&#xff0c;不對或者不妥當不準確的地方必然會有&#xff0c;還懇請大家留言或者郵件我以批評指正&#xff0c;我會虛心接受。謝謝大家。 原文網址&#xff1a;h…

持久化的基于L2正則化和平均滑動模型的MNIST手寫數字識別模型

持久化的基于L2正則化和平均滑動模型的MNIST手寫數字識別模型 覺得有用的話,歡迎一起討論相互學習~Follow Me 參考文獻Tensorflow實戰Google深度學習框架 實驗平臺: Tensorflow1.4.0 python3.5.0MNIST數據集將四個文件下載后放到當前目錄下的MNIST_data文件夾下 定義模型框架與…

怎樣制作滴滴截圖_滴滴老了嗎?

作者 / 薛靜 來源 / 盒飯財經(ID&#xff1a;daxiongfan)滴滴最近有點忙。6月11日&#xff0c;滴滴地圖與公交事業部負責人柴華還在忙于解答消費者對于滴滴司機繞路的質疑&#xff0c;網上就流傳出了滴滴司機直播性侵的消息。當晚&#xff0c;滴滴急忙在官方微博中做出回應稱已…

mysql Backup recovery

如果您要在MySQL數據庫中存儲任何您不想丟失的內容&#xff0c;那么定期備份數據以保護數據免受損失非常重要。本教程將向您展示兩種簡單的方法來備份和恢復MySQL數據庫中的數據。您還可以使用此過程將數據移動到新的Web服務器。 從命令行備份&#xff08;使用mysqldump&#x…

Kinect開發筆記之三Kinect開發環境配置詳解

0、前言&#xff1a;首先說一下我的開發環境&#xff0c;Visual Studio是2013的&#xff0c;系統是win8的64位版本&#xff0c;SDK是Kinect for windows SDK 1.8版本。雖然前一篇博文費了半天勁&#xff0c;翻譯了2.0SDK的新特性&#xff0c;但我還是決定要回退一個版本。其實我…

opencv python 圖像縮放/圖像平移/圖像旋轉/仿射變換/透視變換

Geometric Transformations of Images 1圖像轉換 OpenCV提供了兩個轉換函數cv2.warpAffine和cv2.warpPerspective&#xff0c;可以使用它們進行各種轉換。 cv2.warpAffine采用2x3變換矩陣&#xff0c;而cv2.warpPerspective采用3x3變換矩陣作為輸入。 2圖像縮放 縮放只是調整圖…

.net調用c++方法時如何釋放c++中分配的內存_C/C++編程筆記:C語言編程知識要點總結!大一C語言知識點(全)...

一、C語言程序的構成與C、Java相比&#xff0c;C語言其實很簡單&#xff0c;但卻非常重要。因為它是C、Java的基礎。不把C語言基礎打扎實&#xff0c;很難成為程序員高手。1、C語言的結構先通過一個簡單的例子&#xff0c;把C語言的基礎打牢。C語言的結構要掌握以下幾點&#x…

Django 使用 mysql 數據庫連接

啟用 mysql 數據庫連接 修改 app01 下的 __init__.py import pymysqlpymysql.install_as_MySQLdb() 修改 settings.py DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: django,USER: django,PASSWORD: django,HOST: 192.168.0.200,PORT: 3306,} } 測試 #生成同步…