ipa包大小之linkMap檔案分析

拾雪發表於2017-12-21

近來我們一直在做ipa包大小的縮減,在刪除了無用圖片,縮減專案中圖片的體積,取得了較大的效果。但是成果背後的問題也接踵而至,刪除完了圖片,壓縮完了圖片大小之後我們應該怎麼來減小ipa包大小呢?從哪裡去減小,減小什麼,怎麼減小呢?

帶著這樣的問題,我們先來了解下ipa包的構成: ipa包主要由三大部分構成: ipa包解壓之後 主要由三部分構成: 1.可執行檔案。 2.Asset.car檔案。asset資料夾中圖片的壓縮檔案 3.其他:_CodeSignature資料夾,簽名資訊; 我們之前做的事情主要是縮小2與3中的內容,那麼接下來我們需要縮小的是1的內容了。 既然想要縮減可執行檔案的大小,那麼可執行檔案是這啥這是個什麼東西? 使用file命令檢視 這個可執行檔案; 這是個Mach-O檔案型別,裡面包含了兩個架構:armv7&arm64.

Mach-O? Mach-O格式是個啥?是怎麼組成的? 我們知道Windows下的檔案都是PE檔案,同樣在OS X和iOS中可執行檔案是Mach-O格式的。Mach-O包含三個基本區域: •頭部(header structure)。 •載入命令(load command)。 •段(segment)。可以擁有多個段(segment),每個段可以擁有零個或多個區域(section)。每一個段(segment)都擁有一段虛擬地址對映到程式的地址空間。 •連結資訊。一個完整的使用者級Mach-o檔案的末端是連結資訊。其中包含了動態載入器用來連結可執行檔案或者依賴庫所需使用的符號表,字串表等等。 頭部資訊和載入命令都是用來描述應用程式型別的,連結資訊則是如符號表之類的,所以Mach-O中最重要的部分是這些segment。

segment是啥呢?來看看普通的編譯過程吧: 基本的編譯過程分為四個步驟: 預處理(Pre-process):把巨集替換,刪除註釋,展開標頭檔案,產生 .i 檔案。 編譯(Compliling):使用預處理後的單詞構建詞法樹,生成語法樹輸出AST (Abstract Syntax Tree),將AST轉化成更低階的中間碼(LLVM IR),優化中間程式碼生成輸出彙編程式碼,把之前的 .i 檔案轉換成組合語言,產生 .s檔案。 彙編(Asembly):把組合語言檔案轉換為機器碼檔案,產生 .o 檔案。 連結(Link):對.o檔案中的對於其他的庫的引用的地方進行引用,生成最後的可執行檔案(同時也包括多個 .o 檔案進行 link)

那麼我們知道了Mach-O檔案是一堆segment組成的,而可執行程式是由 .o檔案link而成的,那麼這些.o檔案應該能反應segement的大小,也能反應可執行程式的大小。

好,我們現在的目標變成了去看.o檔案的大小,那麼現在讓我們來看看linkMap。 linkMap開啟是個啥: Mach-O是編譯完成的二進位制檔案,LinkMap是中間產生的如符號表類的檔案,這個LinkMap裡展示了整個可執行檔案的全貌,列出了編譯後的每一個.o目標檔案的資訊(包括靜態連結庫.a裡的),以及每一個目標檔案的程式碼段,資料段儲存詳情。

6C9B65FC-B9F8-4782-AA32-1890C5B09FC0.png

linkMap的結構: linkMap檔案一般有三個部分:1.在LinkMap裡首先列出來的是目標檔案列表:前面中括號裡的是這個檔案的編號,後面會用到,像專案裡引用到靜態連結庫裡的目標檔案都會在這裡列出來。如編號[2]的B.o和編號[5]的A.o

AA112CBA-3253-420F-B42B-E4C951D1E5D8.png

2.接著是一個段表,描述各個段在最後編譯成的可執行檔案中的偏移位置及大小,包括了程式碼段(**TEXT,儲存程式程式碼段編譯後的機器碼)和資料段(DATA,儲存變數值)。 首列是資料在檔案的偏移位置,第二列是這一段佔用大小,第三列是段型別,程式碼段和資料段,第四列是段名稱。 這裡可以清楚看到各種型別的資料在最終可執行檔案裡佔的比例,例如text表示編譯後的程式執行語句,**data表示已初始化的全域性變數和區域性靜態變數,__cstring表示程式碼裡的字串常量,等等。

7E1453C7-EB00-4080-A266-9C87B111CE98.png

每一行的資料都緊跟在上一行後面,如第二行symbol_stub的地址0x100006BD8就是第一行text的地址0×100006A68加上大小0x00000170,整個可執行檔案大致資料分佈就是這樣。 3.接著就是按上表順序,列出具體的按每個檔案列出每個對應欄位的位置和佔用空間。同樣首列是資料在檔案的偏移地址,第二列是佔用大小,第三列是所屬檔案序號,對應上述Object files列表,最後是名字 例如第51行代表了檔案序號為5(反查上面就是A)的function1A方法佔用了4byte大小。5000)

530EFCBB-3BC7-41A7-806E-EC2455881454.png

linkMap的用法: 根據上面的介紹,我們可以把所有file相同的size加起來,就可以得到該檔案的大小了,根據檔案的字首名,就可以得到專案中各個獨立模組的大小了。還可以對兩個迭代得到的linkmap檔案分析結果進行比較就可以得出,這個迭代相比上個迭代新增了多少檔案,減少了多少檔案,哪些檔案比較大需要減小等等資訊。

linkMap檔案的獲取方法:

CB8E5C2D-9FAD-4CD9-8AE4-276DBB396071.png

在xcode中設定編譯選項:XCode -> Project -> Build Settings -> 搜map -> 把Write Link Map File選項設為yes,並在Path to Link Map File中指定好linkMap的儲存位置。 編譯完成之後,即可在儲存位置獲得linkMap檔案。

我這邊寫了個指令碼用於分析LinkMap資訊,並生成Excel。 地址 如有問題 歡迎諮詢。

參考資料: build過程:www.objccn.io/issue-6-1/編譯過程:segmentfault.com/a/119000000… clang & LLVM: kb.cnblogs.com/page/114879… .tbd檔案:www.tuicool.com/articles/Jv… www.cocoachina.com/ios/2016050…

相關文章