- 积分
- 2102
- 最后登录
- 2024-4-24
- 精华
- 1
- 阅读权限
- 220
- 主题
- 288
- UID
- 3081083
- 帖子
- 2708
- PB币
- 90423
- 威望
- 169
- 贡献
- 0
- 技术
- 56
- 活跃
- 2790
这货不是澎湖冰洲
- UID
- 3081083
- 帖子
- 2708
- PB币
- 90423
- 贡献
- 0
- 技术
- 56
- 活跃
- 2790
|
本帖最后由 penghubingzhou 于 2020-4-19 11:27 编辑
各位好,我是澎湖冰洲。上一节我们分析了info.plist里面的内容,以及如何通过KP Log分析出错的代码行。这一节,我们将进入到IOKit具体的细节中去探索。今天的主要内容是IOKit驱动的具体加载机制
通过前面的内容我们已经得知,IOKit是基于c++编写的一套运行于内核层之上的驱动框架,所有的mac驱动,都是基于这个框架来书写的,所有的IOKit驱动都是以一个类的形式来书写的,继承自OSMetaClass类(OOP编程特点)。前面我们说过,由于IOKit驱动是内核层面的东西,因此,STL、多继承、运行时以及异常处理都是无法被支持的。但是对于运行时而言,由于我们存在对驱动对象的处理,所以我们依旧需要一套运行时系统来处理它们。因此,苹果编写了一套全新的高效的运行时系统来处理这些对象。这个功能是基于libkern来实现的,主要功能有:
1、动态对象的分配以及对象的构造与销毁
2、对象的内省与对象的动态转换
3、运行时对象数量跟踪(跟踪每个类当前的实例数)
4、二进制兼容性保护
这些特性全部是基于OSMetaClass来实现的,这个类实际上就是OSObject的对等类,因为这俩都是基于OSMetaClassBase继承的产物。有关这三个类的更多信息,请参见苹果释放的XNU源码中这几个文件的头文件以及cpp文件。
每当我们的类开始加载的时候,libkern框架就会自动执行一整套流程来读取驱动类。因为驱动类都是继承自OSMetaClass的,所以OSMetaClass的加载流程就与驱动类一致。OSMetaClass对于每个类实例使用了四个实例变量来进行描述:
1、类名
2、基类(指向)
3、类规模
4、类当前实例数
当我们的内核开始加载驱动的二进制文件时(位于驱动的Contents/MacOS文件夹下),首先将向运行时系统注册前三位信息。这个系统实际上是一个元类数据库,由两个交叉索引字典组成。一个字典称之为类字典,按类名编制索引;另一个字典称为模块字典,按照驱动二进制文件的名称编制索引。类字典由与OSMetaClass对象配对的类名键组成。它对于动态创建libkern对象(包括驱动程序实例)至关重要。模块字典由驱动二进制名称和二进制文件中的OSMetaClass对象数组组成,这是驱动从内核安全卸载的一个重要部分。
下面这个图说明了当我们的驱动加载时,内核如何把类信息写入字典:
加载IOKit驱动时,加载程序执行元类注册的三个不同阶段:
1、加载前。加载程序调用OSMetaClass成员函数preModLoad。此函数会获取一个锁,以确保在加载多个内核扩展时执行单个线程。它还生成驱动二进制文件中类的全局信息,以准备注册。
2、加载中。加载程序将调用OSMetaClass宏创建的每个静态构造函数,作为类定义的一部分,这时将调用每个类的OSMetaClass构造函数。此构造函数的参数是OSMetaClass数据成员中的三个:类名、指向基类的指针和类大小。加载程序还将更新类和模块字典,使用驱动二进制名称和类名作为字典的键名,并将刚刚创建的OSMetaClass对象插入这些字典中。它还链接了所有继承基类的指针。
3、加载后。加载程序调用OSMetaClass成员函数postModLoad,此函数用于释放锁并返回加载的结果代码。如果此代码指示错误(如构造器格式错误),则将中止加载。
注意:虽然这些用于初始化以及卸载的函数都是Public函数,但你不能在驱动中直接使用这些函数,尤其是preModLoad和postModLoad!!!!
OSObject采用了一种被称为引用计数的机制来管理驱动空间的内存,这个机制类似于其他语言的垃圾回收机制。每当内核代码创建OSObject派生类的实例时,libkern运行时系统都将增加关联OSMetaClass对象的实例引用计数;每当释放实例时,都会减少引用计数。运行时系统使用实例的引用计数来防止卸载系统中具有“活动”对象的内核扩展。当然,如果你的代码没有正确地保留和释放对象,将会出现保留应该卸载的驱动的情况,从而造成内存泄漏的故障。而泄漏的对象引用,不仅将导致烦人的延迟,更严重者会导致驱动停止响应出现KP。
当一个IOKit驱动二进制文件中所有类的引用计数达到零时,驱动的卸载程序将在卸载驱动之前等待一分钟来确保驱动二进制文件不会再次使用。在卸载之前,卸载程序会调用二进制文件中每个类的静态析构函数(free函数),从而从运行时系统中移除对该类的所有引用。
|
附件: 你需要登录才可以下载或查看附件。没有帐号?注册
|