阅读 479

iOS底层探索--dyld与objc的关联

小谷底层探索合集

兄弟们。十一假期玩的爽吗。小生睡了7天,可谓是美滋滋啊。😆

  • 大家对于应用的启动过程应该有些了解了,由于我偷懒(在睡觉),所以就没有写应用启动的博客了)

1. 应用的启动流程简析

我就简单的写下哈。。就不带大家一步一步走了(见谅见谅~),大家有时间的话还是可以调试走一波的。

    1. 我非常努力的画了个图:

有点简陋。

    1. 我们得出结论,应用启动首先调用的是_dyld_start,然后调用objc源码

的第一个方法是_objc_init(这个就是今天要研究的东西~)

2. _objc_init初探

    1. 首先我们看下源码:
void _objc_init(void)
{
    static bool initialized = false;
    if (initialized) return;
    initialized = true;
    
    // fixme defer initialization until an objc-using image is found?
    environ_init();
    tls_init();
    static_init();
    runtime_init();
    exception_init();
    cache_init();
    _imp_implementationWithBlock_init();

    _dyld_objc_notify_register(&map_images, load_images, unmap_image);

#if __OBJC2__
    didCallDyldNotifyRegister = true;
#endif
}
复制代码
    1. 来一波专有名词解释~
environ_init(); 						//环境变量的读取初始化
tls_init(); 							//自动释放池、runloop线程相关
static_init();							//运行C ++静态构造函数
runtime_init();							//新增的。runtime运行时环境初始化
exception_init();						//异常捕获初始化
cache_init();							//缓存条件初始化
_imp_implementationWithBlock_init();	//启动回调机制
复制代码

好吧,以上都不是要探究的重点~😆,这里先不做解释了。

    1. _dyld_objc_notify_register探究

_dyld_objc_notify_register是这次探究的。肉眼可见和dyld有关联~ 我们点进去之后发现:跟不进去了~

3. dyld源码分析

    1. 既然在objc源码中不能继续探究,而且还和dyld有关联,那我们想想一下会不会调用了dyld源码。
    1. 我们打开dyld源码发现:
void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped)
{
     dyld::registerObjCNotifiers(mapped, init, unmapped);
}
复制代码
    1. 既然找到了~ 那我们可以猜测一波:这个是跨库调用(没得办法这个就是这么恶心)
    1. 我们分析下他调用的源码:
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());
         }
     }
}
复制代码
    1. 嘿咻~,这个时候我要截个图了~(代码上写注释,颜色不给力😆)

    1. 那这个的意思:objc源码跨库调用dyld源码,然后dyld源码在调用了objc源码~

4. 应用启动流程图扩展

    1. 我们已经清楚:应用启动首先调用的是_dyld_start,然后调到_objc_init,之后又跨库调用了dyld,然后目的还是调用map_imagesload_images.
    1. 感觉好绕。😭。那么我画了一幅扩展的图:

兄弟们~ 这幅图我尽力了毕竟不是灵魂画家😆