你真的了解dyld么?

有一个工程DyldDemo依赖AB两个动态库,依赖信息如下图所示:

image.png

DyldDemo关键内容

AppDelegate.m:

+ (void)load {
    NSLog(@"AppDelegate load");
}

ViewController.m:

+ (void)load {
    NSLog(@"ViewController load");
}

ViewController+Additions.m:

+ (void)load {
    NSLog(@"ViewController Additions load");
}

AppDelegate+Additions.m:

#import "AppDelegate+Additions.h"

__attribute__((constructor)) void func3() {
    printf("\n ---func3--- \n");
}


__attribute__((constructor)) void func4() {
    printf("\n ---func4--- \n");
}


@implementation AppDelegate (Additions)

+ (void)load {
    NSLog(@"AppDelegate Additions load");
}

@end

main.m:

__attribute__((constructor)) void func1() {
    printf("\n ---func1--- \n");
}


__attribute__((constructor)) void func2() {
    printf("\n ---func2--- \n");
}

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    NSLog(@"---MAIN---");
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

A 关键内容

Compile Sources:

image.png

A1.m:

#import "A1.h"

__attribute__((constructor)) void func_A1() {
    printf("\n ---func_A1--- \n");
}

@implementation A1

+ (void)load {
    NSLog(@"A1 Load");
}

@end

A2.m:

#import "A2.h"

__attribute__((constructor)) void func_A2() {
    printf("\n ---func_A2--- \n");
}


@implementation A2

+ (void)load {
    NSLog(@"A2 Load");
}

@end

A1+Addtions.m:

#import "A1+Addtions.h"

@implementation A1 (Addtions)

+ (void)load {
    NSLog(@"A1 Addtions Load");
}

@end

B 关键内容

Compile Sources:

image.png

B1.m:

#import "B1.h"

__attribute__((constructor)) void func_B1() {
    printf("\n ---func_B1--- \n");
}

@implementation B1

+ (void)load {
    NSLog(@"B1 Load");
}

@end

B2.m:

#import "B2.h"

__attribute__((constructor)) void func_B2() {
    printf("\n ---func_B2--- \n");
}

@implementation B2

+ (void)load {
    NSLog(@"B2 Load");
}

@end


问题:程序运行到[ViewController viewDidLoad]控制台输出什么?

⚠️在Debug环境下,不考虑编译器优化。并且没有进行二进制重排。







问题分析:

  1. 首先初始化B,再初始化A,最后初始化主程序DyldDemo

根据dyld源码可知dyld初始化image list从下标1开始,最后再初始化主程序(下标0)。而image list顺序与Link Binary With Libraries顺序有关。

image.png

dyld相关源码如下:
image.png

  1. B分析
    由于B1.mB2.m前面,所以先执行B1+ load方法。所以B1的输出为:
B1 Load
B2 Load
---func_B1---
---func_B2---

根据dyld的源码可知c++的全局构造函数调用在+load方法之后。
dyld相关源码(ImageLoader::recursiveInitialization):

image.png

  1. A分析
    A中的文件顺序A1+AdditionsA2A1。所以A中的输出应该为:
A2 Load
A1 Load
A1 Addtions Load
---func_A2---
---func_A1---

根据dyldobjc源码可知,分类的+load方法加载是在所有类的+load方法加载后,c++构造函数前调用的。
objc-loadmethod.mm:

image.png

  1. DyldDemo分析
    文件顺序为main.mAppDelegate+AdditionsViewController+AdditionsViewControllerAppDelegate。根据AB的分析同理可得DyldDemo的输出为:
ViewController load
AppDelegate load
AppDelegate Additions load
ViewController Additions load
---func1---
---func2---
---func3---
---func4---
---MAIN---

+load是在objc中调用的,c++全局构造函数是在dyld中调用的,这两个调用都在main函数之前。

  1. 所以整体输出为
B1 Load
B2 Load
---func_B1---
---func_B2---
A2 Load
A1 Load
A1 Addtions Load
---func_A2---
---func_A1---
ViewController load
AppDelegate load
AppDelegate Additions load
ViewController Additions load
---func1---
---func2---
---func3---
---func4---
---MAIN---

运行代码验证:

image.png

总结

  • Dyld初始化image是按Link Binary With Libraries顺序逐个初始化的,从下标1开始,最后再初始化主程序(下标0)。可以理解为是按image进行分组的。
  • image内部是先加载所有类的+ load,再加载分类的+ load,最后加载C++全局构造函数。(类load->分类load->C++构造函数)。+loadobjc中调用的,C++全局构造函数是在dyld中调用的。(在不考虑二进制重排等的优化下,image内部的顺序默认是按Compile Sources中顺序进行的)。
  • main函数是在dyld返回入口函数(main)之后才调用的。

Demo

你可能感兴趣的:(你真的了解dyld么?)