美文网首页
类的加载

类的加载

作者: MrHardy | 来源:发表于2021-07-13 17:46 被阅读0次
    _objc_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);
            _objc_inform("%s is set", opt->env);
        }
    

    打印如下


    OBJC_DISABLE_NONPOINTER_ISA 是什么呢?
    设置环境变量

    设置环境变量


    static_init jump 全部静态C++函数调用
    getLibobjcInitializers jump
    runtime_init jump
    UnattachedCategories jump 独立类别 表
    static UnattachedCategories unattachedCategories;
    allocatedClasses jump 分配的类 表
    init
    exception_init 异常抛出

    installUncaughtSignalExceptionHandler
    数组越界 工程没有崩溃 拦截到了异常


    //重点代码  指针传递 能够同步发生变化 类似于指针拷贝
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    
    map_images jump
    map_images_nolock jump

    未完待续...

    _read_images 重点
    initializeTaggedPointerObfuscator 初始化标记指针模糊器 (混淆)
    //重点代码
     // namedClasses      
    // Preoptimized classes don't go in this table.       
    // 4/3 is NXMapTable's load factor
    //总容积 : 8 * 4 /  3
    //NXCreateMapTable表 add: x =  8 * 4 /  3  * 3 / 4
    
    int namedClassesSize =  (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3; 
    
    gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype,namedClassesSize);  //NXCreateMapTable 创建表
    
     ts.log("IMAGE TIMES: first time tasks");
    
    gdb_objc_realized_classes 表
    //另外的表
        objc::unattachedCategories.init(32);
        objc::allocatedClasses.init();
    
    

    gdb_objc_realized_classes、allocatedClasses这俩表有什么区别呢?



    gdb_objc_realized_classes 总表 不管实现与否,可以是没被开辟过的
    allocatedClasses 总表 已经被开辟过的

    _read_images 下断点

    输出


    sel_registerNameNoLock jump
    __sel_registerName jump
    search_builtins jump _dyld_get_objc_selector
    _read_images-resolvedFutureClasses 已解析的未来类

    在加载的过程中,有的类在读取之后就会被删除掉,但是删除没有删干净,就会出现一些混乱(野指针),也就是残留的类。


    po 打印


    _getObjc2ClassRefs jump
    readClass
              //重点代码
                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);
    

    输出


    加入判断条件



    控制台只输出 readClass - HL - HLPerson

    addNamedClass jump
    addClassTableEntry jump

    待续...

    addNamedClass 里调用 NXMapInsert jump


    _read_images
    //重点代码
          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;
                }
            }
    

    接下来进行试探

    1
        // Realize non-lazy classes (for +load methods and static instances)
        for (EACH_HEADER) {
            classref_t const *classlist = hi->nlclslist(&count);
            for (i = 0; i < count; i++) {
                Class cls = remapClass(classlist[i]);
                if (!cls) continue;
                
                //HL
                const char *mangledName = cls->nonlazyMangledName();
    
                const char *HLPersonName = "HLPerson";
                
                if (strcmp(mangledName, HLPersonName) == 0) {
                    
                    printf("Realize non-lazy-%s - HL - %s\n",__func__,mangledName);
    
                }
                //HL
    
    2
     if (resolvedFutureClasses) {
            for (i = 0; i < resolvedFutureClassCount; i++) {
                Class cls = resolvedFutureClasses[i];
                
                //HL
                const char *mangledName = cls->nonlazyMangledName();
    
                const char *HLPersonName = "HLPerson";
                
                if (strcmp(mangledName, HLPersonName) == 0) {
                    
                    printf("resolvedFutureClasses-%s - HL - %s\n",__func__,mangledName);
    
                }
                //HL
    

    上面两个判断都没进

    realizeClassWithoutSwift 核心重点
    //rw赋值 (ro 赋值给 -> rw)
            rw = objc::zalloc<class_rw_t>();
            rw->set_ro(ro);
            rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
            cls->setData(rw);
    

    setInstancesRequireRawIsa //集合实例需要原始Isa

    DisableNonpointerIsa //环境变量


    继承链 isa走位

    supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);

    添加判断


    没有打印出*$2的地址


    打印


    prepareMethodLists jump
    prepareMethodLists方法里
    fixupMethodList jump
    meth.name jump

    打印ro 未打印出*$2的值


    rwe 什么时候赋值呢?


    realizeAndInitializeIfNeeded_locked jump
    realizeClassMaybeSwiftMaybeRelock jump

    验证了只要是消息发送的时候类方法和实例方法 所属类对象都可以进行加载

    懒加载类情况 数据加载推迟到第一次消息的时候
    lookUpImpOrForward
    realizeClassMaybeSwiftMaybeRelock
    realizeClassWithoutSwift
    methodizeClass

    非懒加载类情况 map_images 的时候加载所有类数据
    redClass
    _getObjc2NonlazyClassList
    realizeClassWithoutSwift
    methodizeClass

    分类是怎么加载的?怎么调用的?

    attachToClass
    methodizeClass 
        // Install methods and properties that the class implements itself.
        method_list_t *list = ro->baseMethods();
        if (list) {
            prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
            if (rwe) rwe->methods.attachLists(&list, 1);
        }
    
     auto rwe = rw->ext();
    
    txt jump
        class_rw_ext_t *ext() const {
            return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
        }
    
        class_rw_ext_t *extAllocIfNeeded() {
            auto v = get_ro_or_rwe();
            if (fastpath(v.is<class_rw_ext_t *>())) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
            } else {
                return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
            }
        }
    

    extAllocIfNeeded jump
    1、attachCategories 添加分类时 调用
    2、class_setVersion设置类版本时
    3、addMethods_finish 添加方法完成时
    4、class_addProtocol 类添加协议
    5、_class_addProperty
    6、objc_duplicateClass

    分类什么时候加载的?
    attachCategories调用 重点
    1、attachToClass
    2、load_categories_nolock

    提出一个疑问为什么要有rwe、rw、ro?三者之间又是怎么样的联系?
    ro clear m沙河路径加载过来的 readonly
    ro 复制一份寸在rw
    rw 脏内存
    运行时功能
    1、添加分类、添加的方法
    2、api addMethods
    ro 是readonly 不能修改,所以就得用rw
    但是并不是每个类都会用到分类,就会产生脏内存,这时候就用到了rwe。
    类里面 有方法 协议 属性 名字 父类

    read_image clas->data

    auto ro = (const class_ro_t *)cls->data();

    打印出 realizeClassWithoutSwift - realizeClassWithoutSwift - HL - HLPerson

    class_getClassMethod jump


    根据格式还原


    auto ro = (const class_ro_t *)cls->data();
    

    自动去找到当前的类型,进行挨个赋值,除非当前的格式地址不匹配无法解析,所以ro从Mach-O里面读到地址指针,可以对class_ro_t的所有相应数据进行赋值。

    rwe赋值
    extAllocIfNeeded


    attachCategories

    methodizeClass方法里3次调用attachToClass


    methodizeClass - previously = nil


    realizeClassWithoutSwift - previously


    attachLists


    观察分类是否已经到主类里面来了


    打印完21个方法,还是没有看到分类的方法

    通过观察发现(method_list_t *) $0 = 0x00007fff80ad89c8 与 [63] = 0x00007fff80ad89c8 是一致的

    p mlists + ATTACH_BUFSIZ - mcount


    p addedLists


    两个值是一样的


    总结
    1: 两个都有 load方法 : _read_images 非赖加载类 - realizeClassWithoutSwift - load_categories_nolock - attachCategories
    2: 分类 load + 主类没有 ( data()里面获取 ) _read_images - realizeClassWithoutSwift - methodizeClass - attachToClass - 没有走 attachCategories
    3: 分类 没有 + 主类 load ( data() ) _read_images - realizeClassWithoutSwift - methodizeClass - attachToClass - 没有走 attachCategories
    4: 两个都没有 main 什么都没有 -> 推迟到 第一次消息发送的时候 初始化 -> data()
    5: 两个都有 load方法 - 很多的分类 (分类不都有load)

    补充

    method_list_t jump

    指针 指向真正的method_t


    method_list_t 继承于 entsize_list_tt

    method_list_t 调用 getOrEnd
    //getOrEnd本类调用
        Element& getOrEnd(uint32_t i) const { 
            ASSERT(i <= count);
            return *PointerModifier::modify(*this, (Element *)((uint8_t *)this + sizeof(*this) + i*entsize()));
        }
        Element& get(uint32_t i) const { 
            ASSERT(i < count);
            return getOrEnd(i);
        }
    

    prepare_load_methods 调用 realizeClassWithoutSwift / _getObjc2NonlazyCategoryList,主类realizeClassWithoutSwift被执行
    ![]](https://img.haomeiwen.com/i6517975/b2433701d77b8f13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    lookUpImpOrForward 里调用了getMethodNoSuper_nolock

    getMethodNoSuper_nolock jump

    //重点
    _object_set_associative_reference jump 对象集关联引用 用来存储


    相关文章

      网友评论

          本文标题:类的加载

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