IOS之二進(jìn)制重拍

原理

App包數(shù)據(jù)并不是在啟動(dòng)的時(shí)候一次全部加載到內(nèi)存中的,而是類(lèi)似于懶加載的方式,以每頁(yè)16KB的數(shù)據(jù)進(jìn)行分頁(yè)加載。啟動(dòng)的時(shí)刻,也是缺頁(yè)加載次數(shù)最多的時(shí)刻。因?yàn)閱?dòng)用到的類(lèi)和方法,并不是全部集中在某幾頁(yè)數(shù)據(jù)中,而是根據(jù)編譯順序,分散到不確定的分頁(yè)數(shù)據(jù)中。我們做二進(jìn)制重拍,也就是要讓啟動(dòng)用到的函數(shù),集中到最前邊的幾張表中,減少分頁(yè)加載的次數(shù),也就節(jié)約了啟動(dòng)時(shí)間。

那么為什么減少分頁(yè)加載的次數(shù),可以節(jié)省啟動(dòng)時(shí)間呢?

這是因?yàn)?,每?yè)數(shù)據(jù)加載到內(nèi)存中,還需要進(jìn)行重綁定的過(guò)程,因?yàn)锳SLR(地址空間布局隨機(jī)化),每次啟動(dòng)后指針地址值并不是MachO中編譯后的地址,還需要加上這個(gè)隨機(jī)偏移地址,也就是rebase(重綁定)的過(guò)程。啟動(dòng)時(shí)刻加載的分頁(yè)越多,重綁定的地址也就越多,拖慢了應(yīng)用的啟動(dòng)時(shí)間。

查看排列順序

① 打開(kāi)編譯配置 Build Settings —> Write Link Map File —> 修改成 YES。

② 打開(kāi)編譯后生產(chǎn)的 .app 文件,在上兩層目錄找 Intermediates.noindex

Intermediates.noindex/xxx(項(xiàng)目根目錄名稱(chēng)).build/Debug-iphoneos/xxx(項(xiàng)目根目錄名稱(chēng)).build/xxx-LinkMap-normal-arm64.txt

這個(gè)txt就是默認(rèn)的排列順序,我們配置.order后,這個(gè)文件的排列順序會(huì)按照.order給定的順序編譯后排序。

配置.order?文件

打開(kāi) Build Setting,搜索 Order File 配置生成的.order文件路徑。

.order里主要寫(xiě)啟動(dòng)時(shí)調(diào)用的方法(獲取在后面會(huì)說(shuō))


?利用插樁獲取重排符號(hào)

注意的是:獲取到符號(hào)表后,以下配置我們就可以刪除掉了。

插樁獲取符號(hào)可以參考LLVM官網(wǎng)的介紹。

原理就是在每一個(gè)OC的方法、函數(shù)、block 的匯編代碼中,插入一條__sanitizer_cov_trace_pc_guard匯編指令,讀取pc寄存器的指令指針,回調(diào)到我們自己添加的C函數(shù)__sanitizer_cov_trace_pc_guard,然后根據(jù)指針恢復(fù)出OC的方法名、函數(shù)名、block。

配置pc寄存器跟蹤配置

Build Settings —> Other C Flags —> 添加?-fsanitize-coverage=trace-pc-guard


引入插樁函數(shù)在AppDelegate里面

#include <stdint.h>

#include <stdio.h>

#include <sanitizer/coverage_interface.h>

#import <dlfcn.h>

#import <libkern/OSAtomic.h>

/*

?- start:起始位置

?- stop:并不是最后一個(gè)符號(hào)的地址,而是整個(gè)符號(hào)表的最后一個(gè)地址,最后一個(gè)符號(hào)的地址=stop-4(因?yàn)槭菑母叩刂吠偷刂纷x取的,且stop是一個(gè)無(wú)符號(hào)int類(lèi)型,占4個(gè)字節(jié))。stop存儲(chǔ)的值是符號(hào)的

?*/

void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? uint32_t*stop) {

? ? staticuint64_tN;

? ? if(start == stop || *start)return;

? ? printf("INIT: %p - %p\n", start, stop);

? ? for(uint32_t*x = start; x < stop; x++) {

? ? ? ? *x = ++N;

? ? }


}

/*

?可以全面hook方法、函數(shù)、以及block調(diào)用,用于捕捉符號(hào),是在多線程進(jìn)行的,這個(gè)方法中只存儲(chǔ)pc,以鏈表的形式


?- guard 是一個(gè)哨兵,告訴我們是第幾個(gè)被調(diào)用的

?*/

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {

//? ? if (!*guard) return;//將load方法過(guò)濾掉了,所以需要注釋掉



? ? //獲取PC

? ? /*

?? ? - PC 當(dāng)前函數(shù)返回上一個(gè)調(diào)用的地址

?? ? - 0 當(dāng)前這個(gè)函數(shù)地址,即當(dāng)前函數(shù)的返回地址

?? ? - 1 當(dāng)前函數(shù)調(diào)用者的地址,即上一個(gè)函數(shù)的返回地址

? ? */

? ? void *PC = __builtin_return_address(0);


? ? Dl_infoinfo;

? ? dladdr(PC, &info);

? ? printf("%s \n", info.dli_sname);

}

然后把打印出來(lái)的方法寫(xiě)入到order文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容