老谭笔记

初探Mac OSX内核开发(一)——创建内核扩展

从事Mac的应用程序开发已经有很长一段时间了,但对于Mac下的内核层编程却一直处于空白状态,每次看到那些写内核扩展的大牛,我都无比崇拜,所以最近下决心来学习学习这方面的知识,同时计划一边学习一边在博客上写心得,加深记忆的同时也希望与大家一同交流,如遇大神路过请一定记得点拨一二~~~

好了,废话不多说了,直接打开Xcode准备进入写代码的节奏,Xcode本身就已经提供了内核扩展和内核驱动的模板,如图:
QQ20131026-1

第一个框中的模板就是内核扩展,第二个框中的模板是驱动模板,他们的区别就是内核扩展会随系统运行而加载,而驱动会因为特定的硬件才会被加载,我们先创建一个内核扩展的工程,然后工程名为TestExtension,然后可以看到工程中会自动创建一个TestExtension.C的文件,并且已经生成了两个方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <mach/mach_types.h>
#include <libkern/libkern.h>
kern_return_t TestExtension_start(kmod_info_t * ki, void *d);
kern_return_t TestExtension_stop(kmod_info_t *ki, void *d);
kern_return_t TestExtension_start(kmod_info_t * ki, void *d)
{
printf("TestExtension Start!\n");
return KERN_SUCCESS;
}
kern_return_t TestExtension_stop(kmod_info_t *ki, void *d)
{
printf("TestExtension Stop!\n");
return KERN_SUCCESS;
}

这两个方法分别会在扩展加载时和卸载时调用,你可能会觉得好奇系统怎么会知道这两个方法的名字呢?其实秘诀就是在工程的配置文件中有两个属性,所以也可以手动去修改这两个方法名并与这两个属性相对应即可,如图:
QQ20131026-3

并注意Info.plist文件中OSBundleLibraries项下面的com.apple.kpi.libkern属性,它对应的是系统内核的版本,你可以通过在命令行中输入uname -r来查看,比如10.9的内核版本为13.0.0。
至此,一个最最简单的内核扩展就已经完成了,编译工程,到build目录下找到编译的后的TestExtension.kext文件,下一步就是怎样加载它了,内核扩展要求文件的所有者是root,用户组是wheel,所以你可以在命令行下通过以下的命令修改文件所有者:

1
sudo chown -R root:wheel TestExtension.kext

然后通过以下的命令加载内核扩展:

1
sudo kextload TestExtension.kext

此时你可以通过控制台程序Console查看到“TestExtension Start!”的输出,说明我们编写的该扩展已经能够正常工作了,在Mac下内核扩展通常都放在/System/Library/Extensions目录下面,所以也建议加载前先将TestExtension.kext移动到该目录。
如果需要卸载该内核扩展,使用以下的命令即可:

1
sudo kextunload TestExtension.kext

同时在控制台也就能看到“TestExtension Stop!”的输出了。

文章相关的Demo示例下载:TestExtension.zip