有很多初始化方法我们通常都是在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/