0
点赞
收藏
分享

微信扫一扫

你真的了解dyld么?

墨春 2021-09-30 阅读 32

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

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:

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:

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
  1. B分析
    由于B1.mB2.m前面,所以先执行B1+ load方法。所以B1的输出为:
B1 Load
B2 Load
---func_B1---
---func_B2---
  1. A分析
    A中的文件顺序A1+AdditionsA2A1。所以A中的输出应该为:
A2 Load
A1 Load
A1 Addtions Load
---func_A2---
---func_A1---
  1. DyldDemo分析
    文件顺序为main.mAppDelegate+AdditionsViewController+AdditionsViewControllerAppDelegate。根据AB的分析同理可得DyldDemo的输出为:
ViewController load
AppDelegate load
AppDelegate Additions load
ViewController Additions load
---func1---
---func2---
---func3---
---func4---
---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---

运行代码验证:

总结

  • 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

举报

相关推荐

0 条评论