Xcode如何找到FrameWork對應的原始碼的
背景描述:
在cocpoads管理下自研庫和第三方的開源庫可以使用frameWork的方式整合到主工程中,在我們編譯過程中,只要不改動pod下整合的庫程式碼,第一次編譯後,第三方庫會編譯成frameWork,通過Xcode 的 buildSetting 的 framework search Path 記錄所有生成的framework地址,在專案的編譯後期去link這些framework 。在沒有修改pod子工程的庫檔案前提下,之後的每一次build都直接link快取中編譯過的framework檔案。但是當檔案編譯成framework,成為了可執行的二進位制檔案,我們卻任然可以藉助Xcode做原始碼除錯。那麼Xcode工具是如何通過一個二進位制檔案執行時找到它對應的原始碼檔案的?
鑑於上個問題,我們可以先看看Xcode的編譯過程
Xcode作為一個GUI工具,實際上是通過呼叫一系列的命令列工具,將命令列工具處理的結果彙總輸出。Xcode 使用clang編譯器進行編譯 會使用一系列 xcrun clang 的命令來編譯檔案,xcrun是用來定位clang工具位置的
接著看編譯過程中都經歷了些什麼?
大致過程如下:
1.檔案預處理
符號化 (Tokenization)
巨集定義的展開
include 的展開
2.語法語義分析
將符號化後的內容轉化為一棵解析樹 (parse tree)
解析樹做語義分析
輸出一棵抽象語法樹(Abstract Syntax Tree* (AST))
3.程式碼生成和優化
將 AST 轉換為更低階的中間碼 (LLVM IR)
對生成的中間碼做優化
生成特定目的碼
輸出彙編程式碼
4.彙編器
將彙編程式碼轉換為目標物件檔案。
5.link檔案
將多個目標物件檔案合併為一個可執行檔案 (或者一個動態庫)
整個過程比較複雜,特別是語義分析,和程式碼優化過程,可以先簡單的看一下與處理過程。clang 有很多命令,可以通過
`$xcrun clang —help `
檢視提示資訊
其中關於預編譯的:
-c Only run preprocess, compile, and assemble steps
-E Only run the preprocessor
我嘗試使用上面的命令預編譯了main.c檔案
main.c檔案:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello World!\n");
return 0;
}
在main.c當前目錄下執行
xcrun clang -E main.c | open -f
Open -f 是將預編譯結果在檔案中開啟,預編譯部分結果截圖如下:
預編譯過程因為要展開所有的巨集定義,inclue , import。 輸出的檔案中行前面的 “#”號 (hash) 接著的數字 代表的插入的原始檔中的行號, 後面的檔案路徑代表的是需要引入的檔案的路徑 後面的數字代表的是引入的內容在新生成的檔案所在的行數,hash下面跟的內容是指定檔案 指定行數 所引入的內容,例如第二張圖中
將 /Application/Xcode.app/Contents/Developer/platforms/MacOSX10.12.sdk/usr/include/machine/_types.h 檔案中的第33行,34行,55行的程式碼段
插入新生成的檔案中。
Xcode也支援檢視檔案的預編譯結果 ,選中檔案點選product—>perform Action —>preprocess,之後便能看到預編譯的結果,可以對比所引入的檔案所在行數和引入的內容是否對應。
Xcode基於預編譯的結果去構建語法樹,生成中間位元組碼,下面是hello world的LLVM中間位元組碼
可以簡單瞭解一下上面llvm中間碼的意思,@符號是LLVM中間位元組碼(IR)的變數字首,@代表全域性變數標誌,%代表區域性變數標誌。@.str是全域性變數名,%cast210 是區域性變數的名稱 。i8, i32,i64代表的儲存位元組型別,char是i8,一個位元組,int是i32,4個位元組。@main,@put,@puts是方法名,在IR中function和全域性變數統稱全域性值(global values)都是@字首標誌。
根據中間位元組碼(LLVM的位元組碼)做程式碼優化,優化後輸出彙編程式碼。
可以使用下面命令來檢視生成的彙編程式碼:xcrun clang -S -o - main.c | open -f
結果如下圖:
按照上面說的步驟,就進入了呼叫匯編器編譯彙編程式碼了,彙編器將彙編程式碼轉換成機器碼,稱為目標物件檔案,在MacOSX, ios下為 Mach-O檔案格式下圖是蘋果官方文件對mach-o檔案格式的介紹:
Mach-O 的組成結構如下圖所示包括了Header、Load commands、Data(包含Segement的具體資料)
我們可以在工程的編譯路徑下找到編譯後生成的可執行檔案APP,我本地路徑為~/Library/Developer/Xcode/DerivedData/App-ackwqnrbjrdvslercxzskjictqru/Build/Intermediates/App.build/Release-iphonesimulator/App.build/Objects-normal/i386
在此路徑下使用size工具檢視檔案結構
xcrun size -x -l -m App
輸出
剛好與蘋果給出的結構圖相匹配,可以暫時先簡單的瞭解下,__TEXT segment 包含了被執行的程式碼,它被以只讀和可執行的方式對映。__DATA segment 中包含了可讀寫資料, 以可讀寫和不可執行的方式對映,它包含了將會被更改的資料。__LINKEDIT segment 包含了動態連結器的原始資料,如符號,字串和重定位的表的入口.
最後進入聯結器連線的階段
連結器解決了目標檔案和庫之間的連結,連結器需要將所需的lib函式(可以理解為系統提供的函式),庫函檔案的記憶體地址編碼進最後的可執行檔案中,接著連結器會輸出可以執行的執行檔案:a.out,得到a.out 命令為:xcrun clang man.c
用size 工具檢視a.out的檔案結構
可以看到 main.c檔案生成的可執行檔案a.out 的虛擬地址空間從0x10000000 開始的,之前的地址是不可訪問
此時在藉助mac下可執行檔案的閱讀器。machOView工具,看生成的a.out的檔案結構和內容,發現了一張叫symbols的表
這裡面就很清楚的記錄了,編譯前的字串,在編譯成二進位制可執行檔案後的虛擬地址,和app打包生成的dsym基本類似,這就可以猜想,蘋果是如何通過crash的二進位制棧資訊解析出可讀性的程式程式碼呼叫棧的。藉助symbols表給我的希望,我用machOView開啟了我編譯生成的frameWork
原諒我把圖片糊得像翔。。。。因為是公司的專案的frameWork
首先第一張裡表示了在不同平臺下的可執行資料,當前frameWork可在ARM,X86,Arm64,X86_64平臺下執行
第二張圖是所有frameWork內的類名對應的編譯生成的虛擬地址
第三張是挑了第二張圖中的一個類的symbols表,記錄的是當前檔案編譯後的字元對照表。
那麼有了以上三張表的對比後我們很容易的瞭解到Xcode工具如何通過執行期間的二進位制地址對應到具體檔案的具體程式碼呼叫了。
相關文章
- python是如何找到對應的package的?PythonPackage
- Win10系統如何找到服務對應的程式_Win10找到服務對應的程式的步驟Win10
- 如何找到SAP ECC事務碼升級到S4HANA後對應的新事務碼
- 直播帶貨app原始碼是如何應對市場挑戰的(附原始碼功能)APP原始碼
- XCode 編譯 PAG 原始碼XCode編譯原始碼
- android原始碼framework下新增新資源的方法Android原始碼Framework
- 從Fresco原始碼中找到非侵入式的答案原始碼
- Android FrameWork 之原始碼編譯AndroidFramework原始碼編譯
- 基於Android5.0的Camera Framework原始碼分析 (三)AndroidFramework原始碼
- 單步除錯找到 cy.visit 的實現原始碼(一) - 找到了 BlueBird除錯原始碼
- 如何找到VEth裝置的對端介面VEth peer
- [編譯原理]如何判斷某文法的二義性以及找到文法對應的語言編譯原理
- django rest framework 檢視原始碼解析DjangoRESTFramework原始碼
- tensorflow原始碼解析之framework-resource原始碼Framework
- tensorflow原始碼解析之framework-allocator原始碼Framework
- SAP Commerce開發之如何找到某個頁面對應的JSP實現頁面JS
- 如何提高 Xcode 的編譯速度XCode編譯
- django-rest-framework原始碼分析2—認證(Authentication)原始碼解析DjangoRESTFramework原始碼
- 面對枯燥的原始碼,如何才能看得下去?原始碼
- Java 如何獲取字元所對應的UniCode編碼Java字元Unicode
- 如何找到真正的 public 方法
- 如何找到埠的程式號
- 從比心APP原始碼的成功,分析陪玩系統原始碼應該如何開發APP原始碼
- 免費的網路教育原始碼能用嗎?應該如何辨別優質的網路教育原始碼?原始碼
- 直播平臺原始碼,針對訊息對話方塊的實際應用效果原始碼
- 單步除錯找到 cy.visit 的實現原始碼(二) - WebSocket?除錯原始碼Web
- Mybatis的初始化和結合Spring Framework後初始化的原始碼探究MyBatisSpringFramework原始碼
- 如何找到 SAP 電商雲 Spartacus UI 產品明細介面對應的 Angular 實現 Component 名稱UIAngular
- Mybatis一級快取和結合Spring Framework後失效的原始碼探究MyBatis快取SpringFramework原始碼
- Xcode debug時如何看crash的call stackXCode
- 如何透過babel去操作ast, 並生成對應的程式碼。BabelAST
- MAC上如何使用Xcode建立應用剪輯呢?MacXCode
- Spring-framework 原始碼匯入 IntelliJ IDEA 記錄SpringFramework原始碼IntelliJIdea
- 如何對 Neuron 原始碼進行交叉編譯原始碼編譯
- 程式設計師是如何從複雜的程式碼裡找到 bug 的?程式設計師
- Django REST framework的請求與響應DjangoRESTFramework
- 如何應對Kubernetes的安全挑戰?
- iOS開發筆記之Xcode9.2下SDK開發-生成Framework的圖解流程iOS筆記XCodeFramework圖解
- 一對一直播廣泛的應用,源自於一對一直播系統原始碼的強大原始碼