美文网首页
iOS底层探索 -- objc与dyld关联分析

iOS底层探索 -- objc与dyld关联分析

作者: iOS小木偶 | 来源:发表于2020-11-17 21:37 被阅读0次

    引子

    在我们之前探索dyld流程时,我们发现其实dyldobjc_init()之间是存在联系的。

    iOS底层探索 -- dyld 流程分析

    其中在我们追踪到_dyld_objc_notify_register 方法时,我们能发现其调用的入口是 _objc_init(), 那么顺着这个线索,我们来看一看这个_objc_init()方法。

    objc_init()

    首先,我们继续使用我们之前的objc源码工程

    我们来看一下objc_init()源码

    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();
        //关于线程key的绑定,例如线程数据的析构函数
        tls_init();
        //运行C++静态构造函数。
        //在dyld调用静态构造函数之前,libc调用了objc_init(),
        //所以我们必须自己动手。
        static_init();
        //runtime运行时环境初始化
        runtime_init();
        //初始化libobjc的异常处理系统。
        //由map_images()调用。
        exception_init();
        //缓存条件的初始化
        cache_init();
        //初始化回调机制。通常情况下,这里不会做什么
        //所有的初始化都是惰性的,但是对于某些进程,我们急切地加载
        _imp_implementationWithBlock_init();
        //注册要在映射、取消映射和初始化objc映像时调用的处理程序。
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    
    #if __OBJC2__
        didCallDyldNotifyRegister = true;
    #endif
    }
    
    

    其中我们能看到中间进行了很多初始化的工作

    • environ_init() 读取环境变量
    • tls_init() 关于线程key的绑定,例如线程数据的析构函数
    • static_init() 运行C++静态构造函数。在dyld调用静态构造函数之前,libc调用了objc_init()所以我们必须自己动手。
    • exception_init() 初始化libobjc的异常处理系统。由map_images()调用。
    • cache_init() 缓存条件的初始化。
    • _imp_implementationWithBlock_init() 初始化回调机制。通常情况下,这里不会做什么。所有的初始化都是惰性的,但是对于某些进程,我们急切地加载
    • _dyld_objc_notify_register() 注册要在映射、取消映射和初始化objc映像时调用的处理程序。

    environ_init()

    void environ_init(void) 
    {
        ....
        // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
        if (PrintHelp  ||  PrintOptions) {
            if (PrintHelp) {
                _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
                _objc_inform("OBJC_HELP: describe available environment variables");
                if (PrintOptions) {
                    _objc_inform("OBJC_HELP is set");
                }
                _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
            }
            if (PrintOptions) {
                _objc_inform("OBJC_PRINT_OPTIONS is set");
            }
            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);
            }
        }
    }
    

    我们发现其中的for()循环可以在满足条件下打印环境标量

    我们想了解到底有哪些环境变量,那我们直接拿出其中的for()循环,并去掉所有条件

    for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
        const option_t *opt = &Settings[I];
         _objc_inform("%s: %s", opt->env, opt->help);
         _objc_inform("%s is set", opt->env);
    }
    

    直接运行,得到打印结果

    objc[3473]: OBJC_PRINT_IMAGES: log image and library names as they are loaded
    objc[3473]: OBJC_PRINT_IMAGES is set
    objc[3473]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps
    objc[3473]: OBJC_PRINT_IMAGE_TIMES is set
    objc[3473]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods
    objc[3473]: OBJC_PRINT_LOAD_METHODS is set
    objc[3473]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods
    objc[3473]: OBJC_PRINT_INITIALIZE_METHODS is set
    objc[3473]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod:
    objc[3473]: OBJC_PRINT_RESOLVED_METHODS is set
    objc[3473]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup
    objc[3473]: OBJC_PRINT_CLASS_SETUP is set
    objc[3473]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup
    objc[3473]: OBJC_PRINT_PROTOCOL_SETUP is set
    objc[3473]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars
    objc[3473]: OBJC_PRINT_IVAR_SETUP is set
    objc[3473]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables
    objc[3473]: OBJC_PRINT_VTABLE_SETUP is set
    objc[3473]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods
    objc[3473]: OBJC_PRINT_VTABLE_IMAGES is set
    objc[3473]: OBJC_PRINT_CACHE_SETUP: log processing of method caches
    objc[3473]: OBJC_PRINT_CACHE_SETUP is set
    objc[3473]: OBJC_PRINT_FUTURE_CLASSES: log use of future classes for toll-free bridging
    objc[3473]: OBJC_PRINT_FUTURE_CLASSES is set
    objc[3473]: OBJC_PRINT_PREOPTIMIZATION: log preoptimization courtesy of dyld shared cache
    objc[3473]: OBJC_PRINT_PREOPTIMIZATION is set
    objc[3473]: OBJC_PRINT_CXX_CTORS: log calls to C++ ctors and dtors for instance variables
    objc[3473]: OBJC_PRINT_CXX_CTORS is set
    objc[3473]: OBJC_PRINT_EXCEPTIONS: log exception handling
    objc[3473]: OBJC_PRINT_EXCEPTIONS is set
    objc[3473]: OBJC_PRINT_EXCEPTION_THROW: log backtrace of every objc_exception_throw()
    objc[3473]: OBJC_PRINT_EXCEPTION_THROW is set
    objc[3473]: OBJC_PRINT_ALT_HANDLERS: log processing of exception alt handlers
    objc[3473]: OBJC_PRINT_ALT_HANDLERS is set
    objc[3473]: OBJC_PRINT_REPLACED_METHODS: log methods replaced by category implementations
    objc[3473]: OBJC_PRINT_REPLACED_METHODS is set
    objc[3473]: OBJC_PRINT_DEPRECATION_WARNINGS: warn about calls to deprecated runtime functions
    objc[3473]: OBJC_PRINT_DEPRECATION_WARNINGS is set
    objc[3473]: OBJC_PRINT_POOL_HIGHWATER: log high-water marks for autorelease pools
    objc[3473]: OBJC_PRINT_POOL_HIGHWATER is set
    objc[3473]: OBJC_PRINT_CUSTOM_CORE: log classes with custom core methods
    objc[3473]: OBJC_PRINT_CUSTOM_CORE is set
    objc[3473]: OBJC_PRINT_CUSTOM_RR: log classes with custom retain/release methods
    objc[3473]: OBJC_PRINT_CUSTOM_RR is set
    objc[3473]: OBJC_PRINT_CUSTOM_AWZ: log classes with custom allocWithZone methods
    objc[3473]: OBJC_PRINT_CUSTOM_AWZ is set
    objc[3473]: OBJC_PRINT_RAW_ISA: log classes that require raw pointer isa fields
    objc[3473]: OBJC_PRINT_RAW_ISA is set
    objc[3473]: OBJC_DEBUG_UNLOAD: warn about poorly-behaving bundles when unloaded
    objc[3473]: OBJC_DEBUG_UNLOAD is set
    objc[3473]: OBJC_DEBUG_FRAGILE_SUPERCLASSES: warn about subclasses that may have been broken by subsequent changes to superclasses
    objc[3473]: OBJC_DEBUG_FRAGILE_SUPERCLASSES is set
    objc[3473]: OBJC_DEBUG_NIL_SYNC: warn about @synchronized(nil), which does no synchronization
    objc[3473]: OBJC_DEBUG_NIL_SYNC is set
    objc[3473]: OBJC_DEBUG_NONFRAGILE_IVARS: capriciously rearrange non-fragile ivars
    objc[3473]: OBJC_DEBUG_NONFRAGILE_IVARS is set
    objc[3473]: OBJC_DEBUG_ALT_HANDLERS: record more info about bad alt handler use
    objc[3473]: OBJC_DEBUG_ALT_HANDLERS is set
    objc[3473]: OBJC_DEBUG_MISSING_POOLS: warn about autorelease with no pool in place, which may be a leak
    objc[3473]: OBJC_DEBUG_MISSING_POOLS is set
    objc[3473]: OBJC_DEBUG_POOL_ALLOCATION: halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools
    objc[3473]: OBJC_DEBUG_POOL_ALLOCATION is set
    objc[3473]: OBJC_DEBUG_DUPLICATE_CLASSES: halt when multiple classes with the same name are present
    objc[3473]: OBJC_DEBUG_DUPLICATE_CLASSES is set
    objc[3473]: OBJC_DEBUG_DONT_CRASH: halt the process by exiting instead of crashing
    objc[3473]: OBJC_DEBUG_DONT_CRASH is set
    objc[3473]: OBJC_DISABLE_VTABLES: disable vtable dispatch
    objc[3473]: OBJC_DISABLE_VTABLES is set
    objc[3473]: OBJC_DISABLE_PREOPTIMIZATION: disable preoptimization courtesy of dyld shared cache
    objc[3473]: OBJC_DISABLE_PREOPTIMIZATION is set
    objc[3473]: OBJC_DISABLE_TAGGED_POINTERS: disable tagged pointer optimization of NSNumber et al.
    objc[3473]: OBJC_DISABLE_TAGGED_POINTERS is set
    objc[3473]: OBJC_DISABLE_TAG_OBFUSCATION: disable obfuscation of tagged pointers
    objc[3473]: OBJC_DISABLE_TAG_OBFUSCATION is set
    objc[3473]: OBJC_DISABLE_NONPOINTER_ISA: disable non-pointer isa fields
    objc[3473]: OBJC_DISABLE_NONPOINTER_ISA is set
    objc[3473]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY: disable safety checks for +initialize after fork
    objc[3473]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY is set
    

    环境变量列表说明:

    变量名 介绍 备注
    OBJC_PRINT_OPTIONS list which options are set 输出OBJC已设置的选项
    OBJC_PRINT_IMAGES log image and library names as they are loaded 输出已load的image信息
    OBJC_PRINT_LOAD_METHODS log calls to class and category +load methods 打印 Class 及 Category 的 + (void)load 方法的调用信息
    OBJC_PRINT_INITIALIZE_METHODS log calls to class +initialize methods 打印 Class 的 + (void)initialize 的调用信息
    OBJC_PRINT_RESOLVED_METHODS log methods created by +resolveClassMethod and +resolveInstanceMethod: 打印通过 +resolveClassMethod: 或 +resolveInstanceMethod: 生成的类方法
    OBJC_PRINT_CLASS_SETUP log progress of class and category setup 打印 Class 及 Category 的设置过程
    OBJC_PRINT_PROTOCOL_SETUP log progress of protocol setup 打印 Protocol 的设置过程
    OBJC_PRINT_IVAR_SETUP log processing of non-fragile ivars 打印 Ivar 的设置过程
    OBJC_PRINT_VTABLE_SETUP log processing of class vtables 打印 vtable 的设置过程
    OBJC_PRINT_VTABLE_IMAGES print vtable images showing overridden methods 打印 vtable 被覆盖的方法
    OBJC_PRINT_CACHE_SETUP log processing of method caches 打印方法缓存的设置过程
    OBJC_PRINT_FUTURE_CLASSES log use of future classes for toll-free bridging 打印从 CFType 无缝转换到 NSObject 将要使用的类(如 CFArrayRef 到 NSArray * )
    OBJC_PRINT_GC log some GC operations 打印一些垃圾回收操作
    OBJC_PRINT_PREOPTIMIZATION log preoptimization courtesy of dyld shared cache 打印 dyld 共享缓存优化前的问候语
    OBJC_PRINT_CXX_CTORS log calls to C++ ctors and dtors for instance variables 打印类实例中的 C++ 对象的构造与析构调用
    OBJC_PRINT_EXCEPTIONS log exception handling 打印异常处理
    OBJC_PRINT_EXCEPTION_THROW log backtrace of every objc_exception_throw() 打印所有异常抛出时的 Backtrace
    OBJC_PRINT_ALT_HANDLERS log processing of exception alt handlers 打印 alt 操作异常处理
    OBJC_PRINT_REPLACED_METHODS log methods replaced by category implementations 打印被 Category 替换的方法
    OBJC_PRINT_DEPRECATION_WARNINGS warn about calls to deprecated runtime functions 打印所有过时的方法调用
    OBJC_PRINT_POOL_HIGHWATER log high-water marks for autorelease pools 打印 autoreleasepool 高水位警告
    OBJC_PRINT_CUSTOM_RR log classes with un-optimized custom retain/release methods 打印含有未优化的自定义 retain/release 方法的类
    OBJC_PRINT_CUSTOM_AWZ log classes with un-optimized custom allocWithZone methods 打印含有未优化的自定义 allocWithZone 方法的类
    OBJC_PRINT_RAW_ISA log classes that require raw pointer isa fields 打印需要访问原始 isa 指针的类
    OBJC_DEBUG_UNLOAD warn about poorly-behaving bundles when unloaded 卸载有不良行为的 Bundle 时打印警告
    OBJC_DEBUG_FRAGILE_SUPERCLASSES warn about subclasses that may have been broken by subsequent changes to superclasses 当子类可能被对父类的修改破坏时打印警告
    OBJC_DEBUG_FINALIZERS warn about classes that implement -dealloc but not -finalize 警告实现了 -dealloc 却没有实现 -finalize 的类
    OBJC_DEBUG_NIL_SYNC warn about @synchronized(nil), which does no synchronization 警告 @synchronized(nil) 调用,这种情况不会加锁
    OBJC_DEBUG_NONFRAGILE_IVARS capriciously rearrange non-fragile ivars 打印突发地重新布置 non-fragile ivars 的行为
    OBJC_DEBUG_ALT_HANDLERS record more info about bad alt handler use 记录更多的 alt 操作错误信息
    OBJC_DEBUG_MISSING_POOLS warn about autorelease with no pool in place, which may be a leak 警告没有 pool 的情况下使用 autorelease,可能内存泄漏
    OBJC_DEBUG_DUPLICATE_CLASSES halt when multiple classes with the same name are present 当出现类重名时停机
    OBJC_USE_INTERNAL_ZONE allocate runtime data in a dedicated malloc zone 在一个专用的 malloc 区分配运行时数据
    OBJC_DISABLE_GC force GC OFF, even if the executable wants it on 强行关闭自动垃圾回收,即使可执行文件需要垃圾回收
    OBJC_DISABLE_VTABLES disable vtable dispatch 关闭 vtable 分发
    OBJC_DISABLE_PREOPTIMIZATION disable preoptimization courtesy of dyld shared cache 关闭 dyld 共享缓存优化前的问候语
    OBJC_DISABLE_TAGGED_POINTERS disable tagged pointer optimization of NSNumber et al. optimization of NSNumber et al. <span class="Apple-tab-span" style="white-space:pre"></span> 关闭 NSNumber 等的 tagged pointer 优化
    OBJC_DISABLE_NONPOINTER_ISA disable non-pointer isa fields 关闭 non-pointer isa 字段的访问

    这些环境变量,我们可以通过Project-> Scheme -> EditScheme -> Run -> Arguments -> Environment Variables 去配置

    环境变量设置.jpg

    通过OBJC_DISABLE_NONPOINTER_ISAOBJC_PRINT_LOAD_METHODS应用举例一下

    OBJC_DISABLE_NONPOINTER_ISA 关闭 non-pointer isa 字段的访问

    测试代码

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            FQPerson *person = [FQPerson alloc];
            [person sayHelloWorld];
    
        }
        return 0;
    }
    
    

    我们在初始化person后加入一个断点 使用lldb调试

    首先我们去除 OBJC_DISABLE_NONPOINTER_ISA

    (lldb) x/4gx person
    0x100752f50: 0x001d800100008735 0x0000000000000000
    0x100752f60: 0x0000000000000000 0x0000000000000000
    (lldb) p/t 0x001d800100008735
    (long) $1 = 0b0000000000011101100000000000000100000000000000001000011100110101
    
    

    然后我们加上OBJC_DISABLE_NONPOINTER_ISA 设置为YES

    (lldb) x/4gx person
    0x100a4a300: 0x0000000100008730 0x0000000000000000
    0x100a4a310: 0x0000000000000000 0x0000000000000000
    (lldb) p/t 0x0000000100008730
    (long) $1 = 0b0000000000000000000000000000000100000000000000001000011100110000
    

    在之前,我们研究isa的信息时

    iOS底层原理探索 -- isa的本质

    我们知道

    # if __arm64__
    #   define ISA_MASK        0x0000000ffffffff8ULL
    #   define ISA_MAGIC_MASK  0x000003f000000001ULL
    #   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    #   define ISA_BITFIELD                                                      \
          uintptr_t nonpointer        : 1;                                       \
          uintptr_t has_assoc         : 1;                                       \
          uintptr_t has_cxx_dtor      : 1;                                       \
          uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
          uintptr_t magic             : 6;                                       \
          uintptr_t weakly_referenced : 1;                                       \
          uintptr_t deallocating      : 1;                                       \
          uintptr_t has_sidetable_rc  : 1;                                       \
          uintptr_t extra_rc          : 19
    #   define RC_ONE   (1ULL<<45)
    #   define RC_HALF  (1ULL<<18)
    # elif __x86_64__
    #   define ISA_MASK        0x00007ffffffffff8ULL
    #   define ISA_MAGIC_MASK  0x001f800000000001ULL
    #   define ISA_MAGIC_VALUE 0x001d800000000001ULL
    #   define ISA_BITFIELD                                                        \
          uintptr_t nonpointer        : 1;                                         \
          uintptr_t has_assoc         : 1;                                         \
          uintptr_t has_cxx_dtor      : 1;                                         \
          uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
          uintptr_t magic             : 6;                                         \
          uintptr_t weakly_referenced : 1;                                         \
          uintptr_t deallocating      : 1;                                         \
          uintptr_t has_sidetable_rc  : 1;                                         \
          uintptr_t extra_rc          : 8
    #   define RC_ONE   (1ULL<<56)
    #   define RC_HALF  (1ULL<<7)
    

    isa的第一位就是代表了nonpointer 信息,两次测试最后一位数值不同,正好符合我们的测试的结果

    OBJC_PRINT_LOAD_METHODS 打印 Class 及 Category 的 + (void)load 方法的调用信息

    同样,我们添加OBJC_PRINT_LOAD_METHODS 并设置值为YES

    运行代码 可以得到打印结果

    objc[9171]: LOAD: class 'OS_xpc_connection' scheduled for +load
    
    ...
    
    objc[9171]: LOAD: category 'NSError(FPAdditions)' scheduled for +load
    objc[9171]: LOAD: +[NSError(FPAdditions) load]
    
    objc[9171]: LOAD: class '_DKEventQuery' scheduled for +load
    objc[9171]: LOAD: +[_DKEventQuery load]
    

    我们再在我们自己的类中也添加一个+ load方法 运行

    objc[9266]: LOAD: class 'OS_xpc_connection' scheduled for +load
    
    ...
    
    objc[9266]: LOAD: class '_DKEventQuery' scheduled for +load
    objc[9266]: LOAD: +[_DKEventQuery load]
    
    objc[9266]: LOAD: class 'FQPerson' scheduled for +load
    objc[9266]: LOAD: +[FQPerson load]
    
    

    此时,我们可以看到多了我们刚刚添加的我们自己类中的load方法

    environ_init()小结

    所以我们可以通过environ_init()的配置,做一下指定处理或者消息检索,在我们开发中可以方便我们去进行优化

    配置项通过终端命令同样可以查看

    $ export OBJC_HELP=1
    

    tls_init()

    这里关于线程key的绑定,例如线程数据的析构函数

    void tls_init(void)
    {
    #if SUPPORT_DIRECT_THREAD_KEYS
        pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
    #else
        _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
    #endif
    }
    

    static_init()

    运行C++静态构造函数。在dyld调用静态构造函数之前,libc调用了objc_init(),所以我们必须自己动手。

    static void static_init()
    {
        size_t count;
        auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
        for (size_t i = 0; i < count; i++) {
            inits[i]();
        }
    }
    

    runtime_init()

    runtime运行时环境初始化

    void runtime_init(void)
    {
        objc::unattachedCategories.init(32);
        objc::allocatedClasses.init();
    }
    

    exception_init()

    初始化libobjc的异常处理系统。由map_images()调用。

    void exception_init(void)
    {
        old_terminate = std::set_terminate(&_objc_terminate);
    }
    

    cache_init()

    缓存条件的初始化

    void cache_init()
    {
    #if HAVE_TASK_RESTARTABLE_RANGES
        mach_msg_type_number_t count = 0;
        kern_return_t kr;
    
        while (objc_restartableRanges[count].location) {
            count++;
        }
    
        kr = task_restartable_ranges_register(mach_task_self(),
                                              objc_restartableRanges, count);
        if (kr == KERN_SUCCESS) return;
        _objc_fatal("task_restartable_ranges_register failed (result 0x%x: %s)",
                    kr, mach_error_string(kr));
    #endif // HAVE_TASK_RESTARTABLE_RANGES
    }
    
    

    _imp_implementationWithBlock_init()

    初始化回调机制。通常情况下,这里不会做什么。所有的初始化都是惰性的,但是对于某些进程,我们急切地加载

    void
    _imp_implementationWithBlock_init(void)
    {
    #if TARGET_OS_OSX
        if (__progname &&
            (strcmp(__progname, "QtWebEngineProcess") == 0 ||
             strcmp(__progname, "Steam Helper") == 0)) {
            Trampolines.Initialize();
        }
    #endif
    }
    

    _dyld_objc_notify_register(&map_images, load_images, unmap_image)

    这是我们需要研究的另一个比较关键的方法

    //注意:只供objc运行时使用
    //注册要在映射、取消映射和初始化objc映像时调用的处理程序。
    //Dyld将用一个包含objc图像信息部分的图像数组来调用“mapped”函数。
    //那些是dylibs的图像的ref计数将自动被缓冲,因此objc将不再需要
    //对它们调用dlopen()以防止它们被卸载。在调用_dyld_objc_notify_register()期间,
    //dyld将使用已经加载的objc图像调用“mapped”函数。在以后的任何dlopen()调用中,
    //dyld还将调用“mapped”函数。Dyld将在调用Dyld时调用“init”函数
    //图像中的初始化器。这时objc调用该映像中的任何+load方法。
    void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                    _dyld_objc_notify_init      init,
                                    _dyld_objc_notify_unmapped  unmapped);
    

    而在其中的三个参数 mapped init unmapped 分别对应的是三个函数

    typedef void (*_dyld_objc_notify_mapped)(unsigned count, const char* const paths[], const struct mach_header* const mh[]);
    typedef void (*_dyld_objc_notify_init)(const char* path, const struct mach_header* mh);
    typedef void (*_dyld_objc_notify_unmapped)(const char* path, const struct mach_header* mh);
    

    那么问题来了,什么时候调用了map_imagesload_images,也就是
    _dyld_objc_notify_mapped_dyld_objc_notify_init 方法

    在我们之前研究dyld的流程时,其中我们讲到过一个方法 notifySingle方法

    loadImage.jpg

    其中sNotifyObjCInit 我们点击跳转一下就能发现

    _dyld_objc_notify_init.jpg

    就是我们之前提到的load_images方法

    notifySingle的调用时机我们之前已经提到过,现在不在赘述。

    但通过上面sNotifyObjCInit我们不由联想到map_images 也就是_dyld_objc_notify_mapped我们也可以去搜索sNotifyObjCMapped去了解其调用的时机。

    通过全局搜索sNotifyObjCMapped,我们可以发现其被调用的地方在notifyBatchPartial

    map_images.jpg

    notifyBatchPartial则在registerObjCNotifiers中被调用。

    registerObjCNotifiers.jpg

    最终入口回到了objc中调用dyld的入口_dyld_objc_notify_register

    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);
    }
    
    

    objcdyld的关联关系大致就在于此。

    借用一张图


    dyld与objc关联图.png

    相关文章

      网友评论

          本文标题:iOS底层探索 -- objc与dyld关联分析

          本文链接:https://www.haomeiwen.com/subject/sgvfiktx.html