Skip to content

Latest commit

 

History

History
132 lines (106 loc) · 4.78 KB

erjinzhichazhuang.md

File metadata and controls

132 lines (106 loc) · 4.78 KB

二进制重排(静态插幢)

1. Apple Clang - Custom Compiler Flags

Other C Flags

-fsanitize-coverage=func,trace-pc-guard

2. Swift Compiler - Custom Flags

如果项目中有Swift的话。 在Other Swift Flags新增2行代码。

-sanitize-coverage=func
-sanitize=undefined

3. 关键代码 将函数执行顺序写入到文件

用到的头文件

#import <dlfcn.h>
#import <libkern/OSAtomic.h>
// 执行每个函数、block 都会将此函数插入到汇编中,上线打包需要将此桩去掉
// 即取出前面的2个配置文件,新增 orderfile 文件。

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.
}

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

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
//    if (!*guard) return;  // Duplicate the guard check.
    /*  精确定位 哪里开始 到哪里结束!  在这里面做判断写条件!*/
    // 取出pc,pc是当前函数、文件地址、等参数结构体的指针。
    // 可以使用dladdr取出来
    void *PC = __builtin_return_address(0);
    SYNode *node = malloc(sizeof(SYNode));
    *node = (SYNode){PC,NULL};
    //进入
    OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
    
//    printf("fname:%s \nfbase:%p \nsname:%s \nsaddr:%p\n",
//           info.dli_fname,
//           info.dli_fbase,
//           info.dli_sname,
//           info.dli_saddr);
//
}


/// 这是将记录的函数写入到文件
    NSMutableArray <NSString *> * symbolNames = [NSMutableArray array];
    
    while (YES) {
        SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode, next));
        if (node == NULL) {
            break;
        }
        Dl_info info;
        dladdr(node->pc, &info);
        NSString * name = @(info.dli_sname);
        BOOL  isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];
        NSString * symbolName = isObjc ? name: [@"_" stringByAppendingString:name];
        [symbolNames addObject:symbolName];
    }
    //取反
    NSEnumerator * emt = [symbolNames reverseObjectEnumerator];
    //去重
    NSMutableArray<NSString *> *funcs = [NSMutableArray arrayWithCapacity:symbolNames.count];
    NSString * name;
    while (name = [emt nextObject]) {
        if (![funcs containsObject:name]) {
            [funcs addObject:name];
        }
    }
    //干掉自己!
    [funcs removeObject:[NSString stringWithFormat:@"%s",__FUNCTION__]];
    //将数组变成字符串
    NSString * funcStr = [funcs  componentsJoinedByString:@"\n"];
    
    NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"setup.order"];
    NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
    NSLog(@"%@",funcStr);

4. Linking

将静态插装生成的order文件复制到工程文件根目录,然后配置下。

让编译函数的顺序按照该文件的先后顺序进行编译,Build Settings->Order File。否则按照Build Phases->Compile Sources的先后顺序进行编译。

./setup.order

5. 查看效果

Instruments->system Trace中测试启动page falut,次数和耗时。

-w1394

总结

二进制重排,在启动的路径触发的page in次数的数量,会影响启动时间,如果page in 次数不上万,则此操作可以忽略,如果达到了10万次级别,则可以尝试。

我们APP 次数平均在2000多次,平均每次page in 0.1ms,一共0.2s,完全在测试不出来。