一.首先探索dyld加载流程
我们初步窥探了dyld的加载流程:
_dyld_start -> dyldbootstrap -> dyld::_main,在dyld::_main流程的最后一步寻找主程序入口,我们进入了recursiveInitialization方法,首先调用了context.notifySingle方法进行单个通知注入,调用回调函数load_images,调用doInitialization方法的时候,会从dyld -> libSystem -> libdispatch -> objc中的_objc_init,_objc_init又调用了dyld中实现的_dyld_objc_notify_register注册回调函数,这样就构成了跨库闭环。
二、_objc_init探索
1、environ_init方法:环境变量初始化
environ_init方法的源码如下,其中的关键代码是 for 循环
void environ_init(void)
{
//...省略部分逻辑
if (PrintHelp || PrintOptions) {
//...省略部分逻辑
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[i];
if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
}
}
}
有以下两种方式可以打印所有的环境变量
-
1、如图。环境变量的设置
Product->Scheme->Edit Scheme, 以OBJC_PRINT_LOAD_METHODS为例设置成YES,打印所有实现了load方法的类2、通过终端命令
export OBJC_hrlp = 1,打印环境变量所以,
OBJC_PRINT_LOAD_METHODS可以监控所有的+load方法,从而处理启动优化(后续会总结下启动优化方法)
2、tls_init:线程key的绑定
主要是本地线程池的初始化以及析构,源码如下
3、static_init:运行系统级别的C++静态构造函数
主要是运行系统级别的C++静态构造函数,在dyld调用我们的静态构造函数之前,libc调用_objc_init方法,即系统级别的C++构造函数 先于 自定义的C++构造函数 运行
4、runtime_init:运行时环境初始化
主要是运行时的初始化,主要分为两部分:分类初始化、类的表初始化(后续会详细讲解对应的函数)
5、exception_init:初始化libobjc的异常处理系统
是初始化libobjc的异常处理系统,注册异常处理的回调,从而监控异常的处理,源码如下
6、cache_init:缓存初始化
7、_imp_implementationWithBlock_init:启动回调机制
该方法主要是启动回调机制,通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待地加载libobjc-trampolines.dylib
7、_dyld_objc_notify_register:dyld注册,垮库调用
方法中的三个参数分别表示的含义如下:
map_images:dyld将image(镜像文件)加载进内存时,会触发该函数
load_image:dyld初始化image会触发该函数
unmap_image:dyld将image移除时,会触发该函数
以上引发了dyld与Objc的关联
===> libobjc源码中--调用
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
1、mapped ===(等价于) map_images
2、init === 等价于 load_images
3、unmapped 等价于 unmap_image
注意:map_images前面有&,属于引用类型,外界条件变,它就会跟着变,要传递值
注意:load_images属于值类型,不传递值
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());
}
}
}
objc把回调函数map_images、load_images、unmap_image分别传给了dyld的sNotifyObjCMapped、sNotifyObjCInit、sNotifyObjCUnmapped
全局搜索sNotifyObjCMapped,发现在notifyBatchPartial方法中调用了sNotifyObjCMapped
static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image_state_change_handler onlyHandler, bool preflightOnly, bool onlyObjCMappedNotification)
{
...
//: -- sNotifyObjCMapped 调用
(*sNotifyObjCMapped)(objcImageCount, paths, mhs);
...
}
在上面的registerObjCNotifiers方法中就对notifyBatchPartial进行了调用,即objc中调用_dyld_objc_notify_register进入dyld后,就会回调map_images,进行镜像文件的映射.这样就构成了跨库闭环,就把objc和dyld进行了关联。