类的加载原理(上)

397 阅读2分钟

_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运行时环境初始化,里面主要是:unattachedCategories,allocatedClasses
    runtime_init();
    //初始化libobjc的异常处理系统
    exception_init();
#if __OBJC2__
    //缓存条件初始化
    cache_t::init();
#endif
    //启动回调机制。通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待地加载trampolines dylib。
    _imp_implementationWithBlock_init();

    //map_images 管理文件中和动态库中所有的符号(class Protocol selector category)
    //load_images 加载执行load方法
    //&map_images 指针传递,跟随变化
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);

#if __OBJC2__
    didCallDyldNotifyRegister = true;
#endif
}

environ_init()环境变量的打印以及使用

environ_init源码里面,打印代码拷贝,取消条件限制,打印所有环境变量。

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

image.png 环境变量使用,Edit Scheme-> Arguments -> Environment Variables image.png 设置OBJC_HELP也可以打印出所有环境变量。

static_init()运行C++静态构造函数

/***********************************************************************
* 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 void static_init()
{
    size_t count;
    auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
    for (size_t i = 0; i < count; i++) {
        inits[i]();
    }
    auto offsets = getLibobjcInitializerOffsets(&_mh_dylib_header, &count);
    for (size_t i = 0; i < count; i++) {
        UnsignedInitializer init(offsets[i]);
        init();
    }
}

runtime_init()

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

初始化unattachedCategoriesallocatedClasses两张表

exception_init()初始化libobjc的异常处理系统

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

static void (*old_terminate)(void) = nil;
static void _objc_terminate(void)
{
    if (PrintExceptions) {
        _objc_inform("EXCEPTIONS: terminating");
    }

    if (! __cxa_current_exception_type()) {
        // No current exception.
        (*old_terminate)();
    }
    else {
        // There is a current exception. Check if it's an objc exception.
        @try {
            __cxa_rethrow();
        } @catch (id e) {
            // It's an objc object. Call Foundation's handler, if any.
            (*uncaught_handler)((id)e);
            (*old_terminate)();
        } @catch (...) {
            // It's not an objc object. Continue to C++ terminate.
            (*old_terminate)();
        }
    }
}

static objc_uncaught_exception_handler uncaught_handler = _objc_default_uncaught_exception_handler;

objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)
{
    objc_uncaught_exception_handler result = uncaught_handler;
    uncaught_handler = fn;
    return result;
}

异常处理

NSSetUncaughtExceptionHandler(&exceptionHandler);//指定异常获取函数

void exceptionHandler(NSException *epx){
    NSLog(@"epx = %@",epx);
}

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

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);
    }
    //省略代码
}

_read_images流程

1: 条件控制进行一次的加载
2: 修复预编译阶段的 @selector 的混乱问题
3: 错误混乱的类处理
4: 修复重映射一些没有被镜像文件加载进来的类
5: 修复一些消息!
6: 当我们类里面有协议的时候 : readProtocol
7: 修复没有被加载的协议
8: 分类处理
9: 类的加载处理
10 : 没有被处理的类 优化那些被侵犯的类

readClass引入

    for (EACH_HEADER) {
        if (! mustReadClasses(hi, hasDyldRoots)) {
            // Image is sufficiently optimized that we need not call readClass()
            continue;
        }

        classref_t const *classlist = _getObjc2ClassList(hi, &count);

        bool headerIsBundle = hi->isBundle();
        bool headerIsPreoptimized = hi->hasPreoptimizedClasses();

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

添加断点 image.png 在这里打印clsnewClsimage.png 发现cls指向的是一个地址,而newCls此时还没有赋值,系统随机给分配了一块脏地址,断点继续往下走,打印 image.png 可以看到readClass之后,指针地址和类关联起来了

readClass探索

image.png 添加截图代码,打上断点,运行程序,查看readClass运行流程,

Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
    const char *mangledName = cls->nonlazyMangledName();
    const char *person = "LKTeacher";
    if (strcmp(mangledName, person) == 0) {
        printf("********%s**********",mangledName);
    }
  
    //代码略
    cls->fixupBackwardDeployingStableSwift();

    Class replacing = nil;
    //代码略
    
    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;
}

发现实际运行流程,并没有加载到ro和rw

  1. cls->fixupBackwardDeployingStableSwift();
  2. addNamedClass(cls, mangledName, replacing);
  3. addClassTableEntry(cls);
  4. return cls;
static void addClassTableEntry(Class cls, bool addMeta = true)
{
    runtimeLock.assertLocked();

    // This class is allowed to be a known class via the shared cache or via
    // data segments, but it is not allowed to be in the dynamic table already.
    auto &set = objc::allocatedClasses.get();

    ASSERT(set.find(cls) == set.end());

    if (!isKnownClass(cls))
        set.insert(cls);
    if (addMeta)
        addClassTableEntry(cls->ISA(), false);
}

添加类的同时,也会添加元类。