iOS底层探索13-dyld探索总结

[TOC]

总结回顾

1:类的加载 – 协议 属性 ro – rw 慢速流程 – 懒加载 – 非懒加载
2:map_images() 什么时候加载
3:load_images() load方法的集合 – cxx + load + main
4:dyld -> main
5:wwdc2017关于dyld2 vs dyld3的一些改变 优化的点 launchclusure避免了一些闭包模式的加载

苹果2020 WWDC 关于Runtime的优化 developer.apple.com/videos/play…
coreFoudation源码: opensource.apple.com/tarballs/CF…
Dyld 拓展补充 WWDC2017 developer.apple.com/videos/play…?

wwdc2017关于dyld2 vs dyld3的一些改变 优化的点 launchclusure避免了一些闭包模式的加载
dyld:developer.apple.com/videos/play…

dyld链接objc的函数执行

dyld如何连接 镜像文件和反向回调
objc源码中 _objc_init() 方法 调用 _dyld_objc_notify_register(&map_images, load_images, unmap_image);
对于&map_images, load_images 如何调用 沟通了objc和dyld的流程 要进行探索

图片.png

在dyld源码中 _dyld_objc_notify_register( 方法 调用 registerObjCNotifiers(

图片.png

图片.png

void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
{
	// record functions to call
	sNotifyObjCMapped	= mapped;
	sNotifyObjCInit		= init;
	sNotifyObjCUnmapped = unmapped;

	// call 'mapped' function with all images mapped so far
	try {
		notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
	}
	catch (const char* msg) {
		// ignore request to abort during registration
	}

	// <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
	for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
		ImageLoader* image = *it;
		if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) {
			dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
			(*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
		}
	}
}
复制代码

registerObjCNotifiers( 方法中有三个重要的赋值

sNotifyObjCMapped	= mapped; //map_images()方法加载
sNotifyObjCInit		= init;          //load_images()方法加载 
sNotifyObjCUnmapped = unmapped;
复制代码

map_images

sNotifyObjCMapped方法 搜索发现 在方法里面调用

try {
		notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
	}
复制代码

图片.png

load_images

sNotifyObjCInit方法

图片.png

递归流程
图片.png

load和cxx和main调用流程

main.m

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

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

__attribute__((constructor)) void kcFunc(){
    printf("来了 : %s \n",__func__);
}
复制代码

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

+ (void)load{
    NSLog(@"%s",__func__);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}


@end

复制代码

结果 1.load 2.c++ 3.main

+[ViewController load]
来了 : lrFunc 
1223333
复制代码

load方法调用探索 load_images() 方法

所有load方法
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
load_images(

图片.png
准备load方法 调用load方法
1.prepare_load_methods((const headerType *)mh);//准备load方法
准备分为 本类load方法 分类的load方法
2.call_load_methods();//调用load方法
调用也分为 本类load方法 分类的load方法

准备load方法 prepare_load_methods((const headerType *)mh);

prepare_load_methods(
图片.png

1.schedule_class_load(remapClass(classlist[i]));//调度类的load方法
2.add_category_to_loadable_list(cat);//调用分类的load方法
先调用类的load方法 后调用分类的load方法

以类的load方法收集为例 探索, 分类的load方法收集过程相似
schedule_class_load(
图片.png

add_class_to_loadable_list(
图片.png

objc_class::getLoadMethod()
图片.png

调用load方法 call_load_methods();

图片.png
调用也是 本类load方法 分类的load方法
call_class_loads();
call_category_loads();

c++方法调用探索

为什么c++方法会自动调用?
bt堆栈调试
图片.png

recursiveInitialization -> doInitialization -> doModInitFunctions -> libSystem_initializer -> libdispatch_init -> _os_object_init -> _objc_init
在这个调用流程上
查阅源码
context.notifySingle(dyld_image_state_dependents_initialized, this, &timingInfo); 方法是load方法的调用
doInitialization 方法是c++主动调用的点

图片.png

doModInitFunctions方法 读取cmd_count 即mach-O里面的东西,

图片.png

main函数调用探索

最后至于main函数如何调用 __dyld_start之后
图片.png

打开汇编 在lrFunc 这个c++方法里面添加断点进行单步调试
单步过掉 load 和 c++方法之后 就到了main方法
此时读取寄存器 register read,会发现main函数在这里, 即main函数调用了

图片.png

图片.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享