底层原理:dyld和objc关联

2020-10-17  本文已影响0人  8ef7f923f5bb

我们在之前的探究过程中发现dyld加载中会调用到_objc_init,这篇文章我们从_objc_init开始研究其具体做了什么。

_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();//环境变量
    tls_init();//线程绑定key
    static_init();//c++静态构造函数运行
    runtime_init();//运行时初始化
    exception_init();//libobjc异常处理
    cache_init();//缓存初始化
    _imp_implementationWithBlock_init();

    // map_images()  load_images()
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
    didCallDyldNotifyRegister = true;
#endif
}

从_objc_init的源码分析,主要分成以下部分:

void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped);

map_images对应mapped,load_images对应init,unmap_image对应unmapped。
从_dyld_objc_notify_register方法定义位于dyld_priv.h文件中,其对应的实现是在dyld的源码中的,在dyld的源码中我们找到了对应的处理

void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped)
{
    log_apis("_dyld_objc_notify_register(%p, %p, %p)\n", mapped, init, unmapped);

    gAllImages.setObjCNotifiers(mapped, init, unmapped);
}

void AllImages::setObjCNotifiers(_dyld_objc_notify_mapped map, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmap)
{
    _objcNotifyMapped   = map;
    _objcNotifyInit     = init;
    _objcNotifyUnmapped = unmap;
  .....
}

从这里我们可以看出,map_images、load_images、unmap_image的调用实现是来自于dyld的。程序运行先是dyld_start链接操作,链接主程序、执行主程序初始化,所有库初始化,然后执行objc_init函数,写入注册函数,通知dyld可以继续执行其他流程。

map_images

void
map_images(unsigned count, const char * const paths[],
           const struct mach_header * const mhdrs[])
{
    mutex_locker_t lock(runtimeLock);
    return map_images_nolock(count, paths, mhdrs);
}

map_images会调用map_images_nolock,map_images_nolock中代码过长我们就不一一贴出来分析了,直接看其最关键的代码

    if (hCount > 0) {
        _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
    }

_read_images从源码分析其实现

    static size_t UnfixedSelectors;
    {
        mutex_locker_t lock(selLock);
        for (EACH_HEADER) {
            if (hi->hasPreoptimizedSelectors()) continue;

            bool isBundle = hi->isBundle();
            SEL *sels = _getObjc2SelectorRefs(hi, &count);
            UnfixedSelectors += count;
            for (i = 0; i < count; i++) {
                const char *name = sel_cname(sels[i]);
                SEL sel = sel_registerNameNoLock(name, isBundle);
                if (sels[i] != sel) {
                    sels[i] = sel;
                }
            }
        }
    }

这段源码中,sels[i] != sel进行带地址的字符串匹配,两者字符会一样但是地址可能不一样。

(lldb) po sels[i]
"class"

(lldb) po sel
"class"

(lldb) p/x sels[i]
(SEL) $3 = 0x000000010045ec5e "class"
(lldb) p/x sel
(SEL) $4 = 0x00007fff77889d1d "class"
(lldb) 
        for (i = 0; i < count; i++) {
            Class cls = (Class)classlist[i];
            Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
            if (newCls != cls  &&  newCls) {
                // Class was moved but not deleted. Currently this occurs 
                // only when the new class resolved a future class.
                // Non-lazily realize the class below.
                resolvedFutureClasses = (Class *)
                    realloc(resolvedFutureClasses, 
                            (resolvedFutureClassCount+1) * sizeof(Class));
                resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
            }
        }

这段代码中我们主要是看readClass,这个方法会读编译器编写的类和元类。cls在这里会由一个地址,经过readClass读取类信息,readClass读取的流程后续再进行分析。

接下来看

for (EACH_HEADER) {
        classref_t const *classlist = 
            _getObjc2NonlazyClassList(hi, &count);
        for (i = 0; i < count; i++) {
            Class cls = remapClass(classlist[i]);
            if (!cls) continue;

            addClassTableEntry(cls);

            if (cls->isSwiftStable()) {
                if (cls->swiftMetadataInitializer()) {
                    _objc_fatal("Swift class %s with a metadata initializer "
                                "is not allowed to be non-lazy",
                                cls->nameForLogging());
                }
                // fixme also disallow relocatable classes
                // We can't disallow all Swift classes because of
                // classes like Swift.__EmptyArrayStorage
            }
            realizeClassWithoutSwift(cls, nil);
        }
    }

这里是分类的加载处理,具体的加载情况及加载时机我们后续再分析。

上一篇 下一篇

猜你喜欢

热点阅读