Hook一切的終極武器--Clang插樁

爲了使用二進制重排優化應用的啓動時間,咱們須要知道應用在啓動時到底執行了哪些方法或函數,經過將這些方法或函數進行重排,並放在.order文件中並配置到項目工程,來達到加快應用啓動時間的目的.有關詳情請查看iOS啓動優化之二進制重排html

這裏有一篇文章介紹了Clang插樁的相關方案node

Clang插樁

在項目工程的以下位置添加-fsanitize-coverage=func,trace-pc-guard的編繹設置的標記:數組

在工程中建立一個文件,並將以下代碼copy到文件中,這裏以我本身建立的文件爲例:xcode

//
//  XJHClangHookFuncTool.m
//  clangDemo
//
//  Created by 熊進輝 on 2020/11/22.
//

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

@implementation XJHClangHookFuncTool
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.
    /*  精肯定位 哪裏開始 到哪裏結束!  在這裏面作判斷寫條件!*/
    
    void *PC = __builtin_return_address(0);
    SYNode *node = malloc(sizeof(SYNode));
    *node = (SYNode){PC,NULL};
    //進入
    OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
    
}


+(NSString *)getClangHookFuncsListFilePath{
    
    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:@"hank.order"];
    NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
    NSLog(@"%@",funcStr);
    return filePath;
}
@end

複製代碼

經過上面建立的類,你就能夠在你工程的第一個界面的viewDidLoad裏面調用getClangHookFuncsListFilePath,從而拿到二進制重排的.order文件了,經過在項目中配置這個文件咱們就完成了二進制重排的啓動優化了。markdown

重排後的方法打印以下: 函數

打開hank.order文件以下: oop

記得把最後一個符號刪除,它是你外部調用的位置,不須要寫進二進制重排裏面。post

若是你是用真機來調試的,那麼你要拿到對應的hank.order文件,方法以下: 打開xcode工程->Window->Devices And Simulators ->選中對應的工程 ->點擊工程列表下的「齒輪」圖標->Download Continaer,而後顯示包內容,到tmp文件夾中找到對應的hank.order文件. 優化

相關文章
相關標籤/搜索