iOS 启动优化

本文只讲操作,原理一带而过。原理可以搜索关键字Clang插桩、二进制重排、Page Fault(缺页异常)

llvm 官方文档:https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards

1.首先在Xcode-Build Settings中搜索other c flag

image

添加参数:-fsanitize-coverage=func,trace-pc-guard

2.添加完成后编译会报错,提示需要实现2个函数:
分别是:

void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
                                                    uint32_t *stop) {
  static uint64_t N;  // Counter for the guards.
  if (start == stop || *start) return;  // Initialize only once.
  printf("INIT: %p %p\n", start, stop);
  for (uint32_t *x = start; x < stop; x++)
    *x = ++N;  // Guards should start from 1.
}

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
  if (!*guard) return;  // Duplicate the guard check.
  // If you set *guard to 0 this code will not be called again for this edge.
  // Now you can get the PC and do whatever you want:
  //   store it somewhere or symbolize it and print right away.
  // The values of `*guard` are as you set them in
  // __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive
  // and use them to dereference an array or a bit vector.
  void *PC = __builtin_return_address(0);
  char PcDescr[1024];
  // This function is a part of the sanitizer run-time.
  // To use it, link with AddressSanitizer or other sanitizer.
  __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
  printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);
}

这两个函数需要引入头文件:

#import <stdint.h>
#import <stdio.h>
#import <sanitizer/coverage_interface.h>

一般来讲,在app启动之后呈现的第一个页面vc中实现这段代码。

下面讲函数的具体实现__sanitizer_cov_trace_pc_guard_init
这个函数不需要做什么,按照官方文档写即可,本质是统计hook了多少个符号,以及所对应的内存地址。

重点是这个函数void __sanitizer_cov_trace_pc_guard(uint32_t *guard)

如果你需要hook + (void) load 请将 if (!*guard) return;注释掉

导入头文件,并定义结构体和原子队列

#import <dlfcn.h>
#import <libkern/OSAtomic.h>

//定义原子队列
static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;
//定义符号结构体
typedef struct {
    void *pc;
    void *next;
} SymbolNode;

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    
//    if (!*guard) return;  
    void *PC = __builtin_return_address(0);
    
    Dl_info info;
    dladdr(PC, &info);
    SymbolNode *node = malloc(sizeof(SymbolNode));
    *node = (SymbolNode){PC, NULL};
    OSAtomicEnqueue(&symbolList, node, offsetof(SymbolNode, next));
    
}

在实现的vc中任意一个函数中继续实现代码,将所有hook到的函数进行排序去重和重命名,并生成 .order 文件,这里以vc中的- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event为例

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //用来存放符号的数组
    NSMutableArray<NSString *> *symbolNames = [NSMutableArray array];
    while (YES) {
        SymbolNode *node = OSAtomicDequeue(&symbolList, offsetof(SymbolNode, next));
        if (node == NULL) {
            break;
        }
        
        Dl_info info;
        dladdr(node->pc, &info);
        
        NSString *name = @(info.dli_sname);

        //是oc方法
        BOOL isObjcSymbol = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];
        
        if (isObjcSymbol) {
            //是oc方法存储到数组中
            [symbolNames addObject:name];
            continue;
        }
        //c++函数
        [symbolNames addObject:[@"_" stringByAppendingString:name]];

    }
    
    
    //反向遍历数组
    NSEnumerator *reverseEm = [symbolNames reverseObjectEnumerator];
    NSMutableArray *funcs = [NSMutableArray arrayWithCapacity:symbolNames.count];
    NSString *name;
    while (name = [reverseEm nextObject]) {
        if (![funcs containsObject:name]) {
            [funcs addObject:name];
        }
    }
    
    //移除当前调用的方法名
    [funcs removeObject:[NSString stringWithFormat:@"%s", __func__]];
    
    //生成order文件

    NSString *symbolString = [funcs componentsJoinedByString:@"\n"];

    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"sorted.order"];
    
    NSData *file = [symbolString dataUsingEncoding:NSUTF8StringEncoding];
    
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:file attributes:nil];
    
    NSLog(@"\n%@", symbolString);

}

3.使用真机编译并启动app,启动完成后点击屏幕看到日志(使用其他方法的需要自己调用其他方法),sorted.order 文件已生成

现在需要找到这个文件,点击 xcode 真机 - add adtional simulators - devices
选择设备


devices@2x.png

右侧选中APP,点击Download Container,并保存

image.png

得到一个xcappdata文件,右键显示包内容,在AppData-tmp目录下,找到sorted.order文件,使用文本编辑打开,如果看到了刚刚和日志一样的内容,那么说明成功了。

下面把这个文件放到工程根目录,同时将刚刚添加的参数-fsanitize-coverage=func,trace-pc-guard删掉,在Xcode-Build Settings中搜索order file

image.png

添加参数 sorted.order 并编译

验证有效性:

Xcode-Build Settings 搜索 link map
Write Link Map File 改为 YES

image.png

编译

xcode左侧products-右键Show in Finder,进入APP目录,往上层找,在
/Intermediates.noindex/工程名.build/Debug-iphoneos/工程名.build中找到名为工程名LinkMap-normal-arm64.txt 文件,打开发现与日志中的函数顺序一致即可。

image.png

至此,Clang插桩完成

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容