美文网首页
类的加载

类的加载

作者: 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 对象集关联引用 用来存储


相关文章

  • 第一章 类加载过程

    要点 类加载过程 类加载器 一、类加载过程 1.类的加载过程 类的加载 .class文件过程分为:加载---->连...

  • 深入理解jvm类加载机制

    1.什么是类加载? 类加载机制一个很大的体系,包括类加载的时机,类加载器,类加载时机。 1.1类加载过程 加载器加...

  • java基础知识之java类加载器

    1. 什么是类加载器 类加载器就是用来加载类的东西!类加载器也是一个类:ClassLoader 类加载器可以被加载...

  • 《深入理解JVM虚拟机》读书笔记-类加载器&Java模块化系统

    类加载器 一.类加载器 1.1 类与类加载器 类加载器的定义: Java虚拟机设计团队有意把 类加载阶段中 的“ ...

  • JVM类加载入门

    一 类加载顺序 class类加载-->验证-->准备--->解析--->初始化 class类加载:通过类加载器加载...

  • 学习笔记 | JAVA的反射(二)

    利用反射机制动态加载类 、获取类的方法、获取类的属性 编译时刻加载类是静态加载类,运行时加载类是动态加载类 正常创...

  • jvm类加载器详解和如何打破双亲委派机制

    类加载过程: 项目启动的时候,并不是加载项目中的所有类,是在使用的时候加载,类加载器加载类的时候首先加载父类,所以...

  • JVM - ClassLoader

    1. 概述 类加载器实际定义了类的namespace。 2.类加载方式之当前类加载器和指定类加载器 类的加载只有两...

  • java-类加载机制

    类的加载机制 主要关注点: 什么是类的加载 类的生命周期 类加载器 双亲委派模型 什么是类的加载 类的加载指的是将...

  • java类加载器及其原理

    java类加载器 : java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器(也叫应用类加载器) ...

网友评论

      本文标题:类的加载

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