iOS自定义初始化方法

有很多初始化方法我们通常都是在applicationDidFinishLaunching里一个个调用,那么有没有办法像__attribute__((constructor)),能够自动调用被修饰的函数?

可以通过指定函数所在section的方式,然后获取section开头去逐个调用。但是这种方法有个问题,你只能获取到第一个函数的开头,但是你不知道它的大小,也就没有办法去依次获取了。

__attribute__((used, section("__TEXT, CustomInit")))
void custom1() {
    NSLog(@"custom1");
}

__attribute__((used, section("__TEXT, CustomInit")))
void custom2() {
    NSLog(@"custom2");
}

- (void)callCustom
{
    Method orginalMethod = class_getClassMethod([self class], _cmd);
    IMP imp = method_getImplementation(orginalMethod);
    Dl_info info;
    if (dladdr((void *)imp, &info)) {
        printf("dli_fname: %s\n", info.dli_fname);
        printf("dli_sname: %s\n", info.dli_sname);
        printf("dli_fbase: %p\n", info.dli_fbase);
        printf("dli_saddr: %p\n", info.dli_saddr);
    } else {
        printf("error: can't find that symbol.\n");
    }
    
    unsigned long funcSize = 0;
    //CustomFunc段的开始
    uint8_t *funcStart = getsectiondata((struct mach_header_64 *)info.dli_fbase, "__TEXT", "CustomInit", &funcSize);
    ((void(*)())funcStart)();
}


所以可以通过声明全局或者静态指针变量,去持有这些函数,把这些指针放到__DATA里自定义的一个段里,因为指针大小都是8字节,每次跳8字节就能访问到下一个指针了。

void custom1() {
    NSLog(@"custom1");
}

void(*customVar1)(void) __attribute__((used, section("__TEXT, CustomInit")))  = custom1;

void custom2() {
    NSLog(@"custom2");
}

void(*customVar2)(void) __attribute__((used, section("__TEXT, CustomInit")))  = custom1;


- (void)callCustom
{
    Method orginalMethod = class_getClassMethod([self class], _cmd);
    IMP imp = method_getImplementation(orginalMethod);
    Dl_info info;
    if (dladdr((void *)imp, &info)) {
        printf("dli_fname: %s\n", info.dli_fname);
        printf("dli_sname: %s\n", info.dli_sname);
        printf("dli_fbase: %p\n", info.dli_fbase);
        printf("dli_saddr: %p\n", info.dli_saddr);
    } else {
        printf("error: can't find that symbol.\n");
    }
    unsigned long size = 0;
    uint8_t *start = getsectiondata((struct mach_header_64 *)info.dli_fbase, "__DATA", "CustomInit", &size);
        int funcCount = size/sizeof(void *);
    for (int i=0;i<funcCount; i++) {
        //这里要用指针的指针
        void(**f)() = (void(**)())start + i;
        (*f)();
    }
}

这样声明函数和变量太麻烦了,我们可以使用宏来帮忙。

#define CustomInitFuncBegin(funcName) \
void funcName() {

#define CustomInitFuncEnd(funcName) }\
static void (*funcName##_var)() __attribute__((used, section("__DATA, CustomInit")))  = funcName;


CustomInitFuncBegin(init1)
NSLog("测试init1\n");
CustomInitFuncEnd(init1)

CustomInitFuncBegin(init2);
NSLog("测试init2\n");
CustomInitFuncEnd(init2);


+ (void)callCustom
{
    Method orginalMethod = class_getClassMethod([self class], _cmd);
    IMP imp = method_getImplementation(orginalMethod);
    Dl_info info;
    if (dladdr((void *)imp, &info)) {
        printf("dli_fname: %s\n", info.dli_fname);
        printf("dli_sname: %s\n", info.dli_sname);
        printf("dli_fbase: %p\n", info.dli_fbase);
        printf("dli_saddr: %p\n", info.dli_saddr);
    } else {
        printf("error: can't find that symbol.\n");
    }
    unsigned long size = 0;
    uint8_t *start = getsectiondata((struct mach_header_64 *)info.dli_fbase, "__DATA", "CustomInit", &size);
    int funcCount = size/sizeof(void *);
    for (int i=0;i<funcCount; i++) {
        void(**f)() = (void(**)())start + i;
        (*f)();
    }
}

参考:

https://everettjf.github.io/2017/03/06/a-method-of-delay-premain-code/

相关推荐

  1. iOS定义初始化方法

    2024-04-09 17:54:01       30 阅读
  2. 使用 Gradle 定义任务生成初始化 SQL 文件

    2024-04-09 17:54:01       37 阅读
  3. IOS 纯代码定义UIView案例

    2024-04-09 17:54:01       30 阅读
  4. Python jupyter notebook 定义魔术方法

    2024-04-09 17:54:01       50 阅读
  5. element ui 添加定义方法

    2024-04-09 17:54:01       32 阅读
  6. MFC 定义分发消息方法

    2024-04-09 17:54:01       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-09 17:54:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-09 17:54:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-09 17:54:01       82 阅读
  4. Python语言-面向对象

    2024-04-09 17:54:01       91 阅读

热门阅读

  1. 在Windows系统上下载并安装MySQL的详细教程

    2024-04-09 17:54:01       35 阅读
  2. 本地文件转为MultipartFile,图片地址转MultipartFile

    2024-04-09 17:54:01       37 阅读
  3. 如何动态往Spring容器注册/移除bean?

    2024-04-09 17:54:01       33 阅读
  4. pe格式从入门到图形化显示(五)-RVA和FOA

    2024-04-09 17:54:01       36 阅读
  5. 记一个Unity的异常问题

    2024-04-09 17:54:01       37 阅读
  6. UVA10391 Compound Words 复合词 解题报告

    2024-04-09 17:54:01       27 阅读
  7. Python入门:轻松学习,编程不再难

    2024-04-09 17:54:01       35 阅读
  8. 云智前端面试题

    2024-04-09 17:54:01       31 阅读
  9. 服务器硬件基础知识解析

    2024-04-09 17:54:01       31 阅读
  10. Vue.nextTick() 使用场景及实现原理

    2024-04-09 17:54:01       37 阅读
  11. DockerFile定制镜像

    2024-04-09 17:54:01       32 阅读
  12. Vue3 · 小白学习全局 API:常规

    2024-04-09 17:54:01       36 阅读