美文网首页
dyld和objc的关联

dyld和objc的关联

作者: 大橘猪猪侠 | 来源:发表于2020-10-13 18:05 被阅读0次

在描述dyld和objc的关联之前,我们需要先了解什么是dyld,在APP启动过程中,会将程序中的静态库动态库编译打包成可执行文件Mach-o文件,而被编译的文件就由dyld负责连接、加载进入主程序。那么关于dyld的详细流程介绍,可以参考这个大神的博客

其实也就是dyld将库、代码进行编译,加载到内存中。

探究dyldobjc的关联,首先需要准备两份资料,分别是objc4-781源码dyld源码。他们都可以在苹果官方文档中下载,其中objc4-781源码是经过调试可编译的代码

既然dyld会将库进行加载,那么dyld也会将objc加载到内存中,而objc代码中主要由objc_init进行初始化。

先来看看objc_init方法的源码:

iShot2020-10-13 15.30.00.png

在上图中,是objc_init的方法实现,在里面调用了很多其他的方法。

我们来看一下第一个函数environ_init();的代码实现,里面有很多环境变量的设置;
看下图所示(部分代码):

iShot2020-10-13 15.37.33.png

可以看到红色方框中的代码,我们对里面的代码稍微进行修改:


iShot2020-10-13 15.39.51.png

将下面的for循环代码复制到上面,并将判断去掉,运行程序:

iShot2020-10-13 15.41.53.png

上图是打印的所有环境变量的信息(一部分)。

下面来进行一个小测试,将OBJC_DISABLE_NONPOINTER_ISA的值设为YES,也就是说,这个值的设置,就杜绝生成NONPOINTER_ISA,就意味着都是为普通的isa

iShot2020-10-13 15.44.00.png

在设置OBJC_DISABLE_NONPOINTER_ISA环境变量之后,通过对类信息进行打印,得到的$1末尾为0:

iShot2020-10-13 15.54.09.png

下面去掉设置的环境变量,对类信息打印:


iShot2020-10-13 15.54.48.png

$1的末尾为1,也就是说去掉了环境变量,就直接影响到了NONPOINTER_ISA,让他不会生成NONPOINTER_ISA的结构.

获取你还不理解上面的意思,现在换OBJC_PRINT_LOAD_METHODS环境变量设置输出,同时将上面设置的打印环境变量代码注释掉,运行程序:

iShot2020-10-13 16.01.57.png

看上图,可以看到系统的很多load方法名被打印了出来(只截取一部分输出结果)。
而当我们自己在类中写load方法,它同样也会打印出来,那么这样设置的好处就显而易见,通过控制环境变量,来获取我们想要的信息。

介绍完environ_init();函数之后,下面的一些部分函数我这边就不去一一探索了,跟dyldobjc的关联关系都不大。

直接跳转到_dyld_objc_notify_register(&map_images, load_images, unmap_image)函数。这就是dyld注册的地方,也是重点中的重点。

当我们想要点击这个函数的实现时,在objc源码中却只有声明,没有实现。
&map_images引用函数类型,当map_images的内容发生改变,传入的值也会发生改变。
images是镜像文件,不是图片的意思。
map_images是映射镜像文件
load_images是加载镜像文件

下面我们就需要去dyld的源码中去继续探索,通过全局搜索_dyld_objc_notify_register,就可以找到这个方法的实现,如下图所示:

iShot2020-10-13 16.32.52.png

其中,mapped=map_imagesinit = load_imagesunmapped=unmap_image

iShot2020-10-13 16.35.16.png

因此,我们就可以去查看在objc中的_dyld_objc_notify_register方法中的参数实现是来源于dyld中的。

sNotifyObjCMapped的实现:

iShot2020-10-13 16.39.12.png

sNotifyObjCInit的实现

iShot2020-10-13 16.38.07.png
因此,得到一个结论,首先dyld_start进行一系列初始化,弱引用,连接等等一系列操作之后开始主程序初始化,初始化所有库,之后就进入objc_init函数,写入注册函数,告诉dyld可以继续执行其他流程。

下面我们来探索一下map_imagesload_images做了些什么:

下图是map_images的源码实现,其中红色方框中是重点:

iShot2020-10-13 16.48.23.png

_read_images函数中的代码很多,有很多判断,都是对一些事情的处理:
(部分代码)

iShot2020-10-13 16.59.30.png iShot2020-10-13 16.59.53.png
函数中代码实现的作用:

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

下面选几个代码块进行探索,如下图所示,此函数的作用是修复预编译阶段的 @selector 的混乱问题,它不是简单的字符串匹配,而是带地址的字符串匹配,从图片中可以看到,sels[i]sel对于匹配字符串是一摸一样的,但是对地址来说,他们是不一样的。

iShot2020-10-13 17.15.06.png

下图是对预编译过程中类信息混乱进行处理,从lldb调试过程中,if (newCls != cls && newCls)判断并没有进入,因此,这是一个处理过程,当没有出现混乱时,就不会进入此判断。

iShot2020-10-13 17.20.42.png 而有一个更有意思的东西,如下图所示 iShot2020-10-13 17.23.15.png

当我们在newCls处打断点,在控制台打印cls的名字时,它只输出了地址,而执行完readClass之后,才可以打印cls的名字,可以看出,readClass是读取类信息。

继续执行程序,当进入if (!noClassesRemapped())判断时,里面的代码并没有执行,因此,我们可以忽略这处代码块。

之后的很多判断,里面的功能在上面都已经详细介绍了,当程序中没有涉及到相应的内容时,在_read_images并不会去执行相应的代码块。

下面我们去探索一下readClass是如何去读取类信息的:

iShot2020-10-13 17.38.13.png

从上图可以看到,我们可以用readClass打印所有的方法名;在我们实际开发中,我们就可以利用这个判断某一个方法是否存在,如下图所示:

iShot2020-10-13 17.41.16.png

mangledName源码实现:

iShot2020-10-13 17.48.04.png

从上图可以得出,当类已经初始化完毕之后,才会从ro里面获取,不然就只能从Mach-o中的内存中去读取信息。

当函数继续向下执行过程中,可以看到下图3228-3234行代码中,可以看到类信息的赋值,而当我们程序执行时,却并不会执行这一块区域的代码,直接跳转到3242行代码处,这是一个很神奇的地方,如果代码不能调试,你或许会认为这里会对读取类信息。


iShot2020-10-13 17.43.46.png

继续执行程序:


iShot2020-10-13 17.52.49.png

addClassTableEntry源码:

iShot2020-10-13 17.52.22.png

从上面两图得到的结论是:当所有数据还在Mach-o中,从Mach-o中读取信息到ClassTable表当中,这样在内存当中,就会读取到这个类。

相关文章

  • dyld和objc关联

    上一篇我们讲述了dyld的加载流程 这篇文章我们来搞清楚dyld和objc的关联。 首先看一下objc4-781官...

  • dyld与objc的关联

    在本篇文章中,主要探索dyld与objc是如何关联的。 objc_init _objc_init通过dyld的消息...

  • 十二、dyld 和 Objc 的关联

    主要内容:一、_objc_init 源码分析二、dyld 和 Objc 的关联 一、_objc_init 源码分析...

  • OC底层原理11—dyld与objc的关联

    本文介绍dyld与objc的关联 按照苹果的解释,dyld加载库时,libSystem会调用_objc_init,...

  • dyld和objc的关联

    一、objc 查看objc源码的时候看到了void _objc_init(void)函数 那这个方法什么时候进来的...

  • dyld和objc的关联

    在描述dyld和objc的关联之前,我们需要先了解什么是dyld,在APP启动过程中,会将程序中的静态库和动态库编...

  • dyld 和Objc 的关联

    一 ,引言 前边我们已经学习了iOS开发过程中的相关程序启动的重要角色dyld,通过dyld帮助我们做了很多准备的...

  • dyld和ObjC的关联

    在iOS dyld加载流程[https://www.jianshu.com/p/bda67b2a3465]里我们讲...

  • dyld和objc的关联

    接下来让我们一起探索dyld和objc的关联首先查看objc_init源码 environ_init():读取影响...

  • dyld和objc的关联

    dyld(the dynamic link editor),也就是动态链接器,是内核在完成进程工作后,需要将需要的...

网友评论

      本文标题:dyld和objc的关联

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