IOS之二进制重拍

源代码 2024-10-6 18:04:28 30 0 来自 中国
原理
App包数据并不是在启动的时间一次全部加载到内存中的,而是雷同于懒加载的方式,以每页16KB的数据举行分页加载。启动的时间,也是缺页加载次数最多的时间。由于启动用到的类和方法,并不是全部会合在某几页数据中,而是根据编译顺序,分散到不确定的分页数据中。我们做二进制重拍,也就是要让启动用到的函数,会合到最前边的几张表中,镌汰分页加载的次数,也就节省了启动时间。
那么为什么镌汰分页加载的次数,可以节流启动时间呢?
这是由于,每页数据加载到内存中,还必要举行重绑定的过程,由于ASLR(地址空间结构随机化),每次启动后指针地址值并不是MachO中编译后的地址,还必要加上这个随机偏移地址,也就是rebase(重绑定)的过程。启动时间加载的分页越多,重绑定的地址也就越多,拖慢了应用的启动时间。
查看分列顺序
① 打开编译设置 Build Settings —> Write Link Map File —> 修改成 YES。
② 打开编译后生产的 .app 文件,在上两层目次找 Intermediates.noindex
Intermediates.noindex/xxx(项目根目次名称).build/Debug-iphoneos/xxx(项目根目次名称).build/xxx-LinkMap-normal-arm64.txt
这个txt就是默认的分列顺序,我们设置.order后,这个文件的分列顺序会按照.order给定的顺序编译后排序。
2.png 3.png 设置.order 文件
打开 Build Setting,搜索 Order File 设置天生的.order文件路径。
.order里告急写启动时调用的方法(获取在背面会说)


 利用插桩获取重排符号
注意的是:获取到符号表后,以下设置我们就可以删撤除了。
插桩获取符号可以参考LLVM官网的先容。
原理就是在每一个OC的方法、函数、block 的汇编代码中,插入一条__sanitizer_cov_trace_pc_guard汇编指令,读取pc寄存器的指令指针,回调到我们本身添加的C函数__sanitizer_cov_trace_pc_guard,然后根据指针规复出OC的方法名、函数名、block。
设置pc寄存器跟踪设置
Build Settings —> Other C Flags —> 添加 -fsanitize-coverage=trace-pc-guard


引入插桩函数在AppDelegate内里
#include <stdint.h>
#include <stdio.h>
#include <sanitizer/coverage_interface.h>
#import <dlfcn.h>
#import <libkern/OSAtomic.h>
/*
 - start:起始位置
 - stop:并不是末了一个符号的地址,而是整个符号表的末了一个地址,末了一个符号的地址=stop-4(由于是从高地址往低地址读取的,且stop是一个无符号int范例,占4个字节)。stop存储的值是符号的
 */
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方法、函数、以及block调用,用于捕获符号,是在多线程举行的,这个方法中只存储pc,以链表的情势


 - guard 是一个哨兵,告诉我们是第几个被调用的
 */
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
//    if (!*guard) return;//将load方法过滤掉了,以是必要表明掉




    //获取PC
    /*
     - PC 当前函数返回上一个调用的地址
     - 0 当前这个函数地址,即当前函数的返回地址
     - 1 当前函数调用者的地址,即上一个函数的返回地址
    */
    void *PC = __builtin_return_address(0);


    Dl_infoinfo;
    dladdr(PC, &info);
    printf("%s \n", info.dli_sname);
}
然后把打印出来的方法写入到order文件
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 16:45, Processed in 0.172636 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表