OC底层原理(14)- 类的加载原理(上)

125 阅读2分钟

objc_init分析

objc_init源码

/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/

__attribute__((constructor)) void objcFunc(){
    printf("来了 : %s \n",__func__);
}

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();//环境变量的初始化,可以通过在xode中配置相关的环境变量开关,查看需要的信息
    tls_init();//线程相关
    
/****************************************************
* static_init
* Run C++ static constructor functions.
* libc calls _objc_init() before dyld would call our static constructors, 
* so we have to do it ourselves.
***************************************************/
    static_init();//c++全局构造函数调用
    
    runtime_init();
    
    /**************************************************
* exception_init
* Initialize libobjc's exception handling system.
* Called by map_images().
************************************************/
    exception_init();
#if __OBJC2__
    cache_t::init();//缓存条件初始化
#endif
    _imp_implementationWithBlock_init();

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

打印环境变量帮助:代码资源

以上相关函数的解释:

image.png

_dyld_objc_notify_register

image.png

read_images流程

map_images

/***********************************************************************
* map_images
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLock
**********************************************************************/
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_nolock
* Process the given images which are being mapped in by dyld.
* All class registration and fixups are performed (or deferred pending
* discovery of missing superclasses etc), and +load methods are called.
*
* info[] is in bottom-up order i.e. libobjc will be earlier in the 
* array than any library that links to libobjc.
*
* Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
**********************************************************************/
void 
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                  const struct mach_header * const mhdrs[])
{
    ...
    if (hCount > 0) {
        _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
    }

    firstTime = NO;
    
    // Call image load funcs after everything is set up.
    for (auto func : loadImageFuncs) {
        for (uint32_t i = 0; i < mhCount; i++) {
            func(mhdrs[i]);
        }
    }
}

read_images

read_images源码

/*********************************************************
* _read_images
* Perform initial processing of the headers in the linked 
* list beginning with headerList. 
*
* Called by: map_images_nolock
*
* Locking: runtimeLock acquired by map_images
***********************************************************/
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{

    ...
    ts.log("IMAGE TIMES: first time tasks");
    ts.log("IMAGE TIMES: fix up selector references");
    ts.log("IMAGE TIMES: discover classes");
    ts.log("IMAGE TIMES: remap classes");
    ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
    ts.log("IMAGE TIMES: discover protocols");
    ts.log("IMAGE TIMES: fix up @protocol references");
    ts.log("IMAGE TIMES: discover categories");
    ts.log("IMAGE TIMES: realize non-lazy classes");
    ts.log("IMAGE TIMES: realize future classes");
    ...

}

image.png

readClass分析

/***********************************************************************
* readClass
* Read a class and metaclass as written by a compiler.
* Returns the new class pointer. This could be: 
* - cls
* - nil  (cls has a missing weak-linked superclass)
* - something else (space for this class was reserved by a future class)
*
* Note that all work performed by this function is preflighted by 
* mustReadClasses(). Do not change this function without updating that one.
*
* Locking: runtimeLock acquired by map_images or objc_readClassPair
**********************************************************************/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
    const char *mangledName = cls->nonlazyMangledName();
    const char *LGPersonName = "LGPerson";
    if (strcmp(mangledName, LGPersonName) == 0) {
        // 自己写得类,是如何加载到内存的
        printf("%s -KC: 要研究的: - %s\n",__func__,mangledName);
    }
    ...
    cls->fixupBackwardDeployingStableSwift();


    //自己写的类不会进入下面的判断里面
    Class replacing = nil;
    if (mangledName != nullptr) {
        if (Class newCls = popFutureNamedClass(mangledName)) {
            // This name was previously allocated as a future class.
            // Copy objc_class to future class's struct.
            // Preserve future's rw data block.

            if (newCls->isAnySwift()) {
                _objc_fatal("Can't complete future class request for '%s' "
                            "because the real class is too big.",
                            cls->nameForLogging());
            }

            class_rw_t *rw = newCls->data();
            const class_ro_t *old_ro = rw->ro();
            memcpy(newCls, cls, sizeof(objc_class));

            // Manually set address-discriminated ptrauthed fields
            // so that newCls gets the correct signatures.
            newCls->setSuperclass(cls->getSuperclass());
            newCls->initIsa(cls->getIsa());

            rw->set_ro((class_ro_t *)newCls->data());
            newCls->setData(rw);
            freeIfMutable((char *)old_ro->getName());
            free((void *)old_ro);

            addRemappedClass(cls, newCls);

            replacing = cls;
            cls = newCls;
        }
    }
    
    if (headerIsPreoptimized  &&  !replacing) {
        // class list built in shared cache
        // fixme strict assert doesn't work because of duplicates
        // ASSERT(cls == getClass(name));
        ASSERT(mangledName == nullptr || getClassExceptSomeSwift(mangledName));
    } else {
        if (mangledName) { //some Swift generic classes can lazily generate their names
            addNamedClass(cls, mangledName, replacing);
        } else {
            Class meta = cls->ISA();
            const class_ro_t *metaRO = meta->bits.safe_ro();
            ASSERT(metaRO->getNonMetaclass() && "Metaclass with lazy name must have a pointer to the corresponding nonmetaclass.");
            ASSERT(metaRO->getNonMetaclass() == cls && "Metaclass nonmetaclass pointer must equal the original class.");
        }
        addClassTableEntry(cls);
    }

    // for future reference: shared cache never contains MH_BUNDLEs
    if (headerIsBundle) {
        cls->data()->flags |= RO_FROM_BUNDLE;
        cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
    }
    
    return cls;
}

小结

本次知识内容,从 dyld 进入 objc_init, 重点分析了 objc_init 内部的部分方法,包括一些初始化的内容,其中重点是 _dyld_objc_notify_register ,在这里有两个重要的方法执行 map_imagesload_images,然后深入分析了 map_images方法,接下来继续探索map_images里面的内容。