实 验 名 称 | 内核模块编写 |
- 实验目的
(1)理解操作系统中缺页中断的工作原理。
(2)学会通过修改内核实现统计系统缺页次数的方法。
- 实验内容
通过修改 Linux内核中的相关代码,统计系统缺页次数。
- 实验步骤
(1)编写内核模块源代码文件 helloworld.c。
(2)编写编译内核模块时要用到的Makefile文件。
(3)编译 helloworld.c。
(4)执行内核模块装入命令。
(5)当不需要使用helloworld 模块时,就载这个模块。
- 实验结果
(1)执行内核模块装人命令。
# sudo insmod helloworld,ko
可以通过 dmesg命令查看控制台输出,如图所示。
# dmesg
这时,可以看到输出结果“<1>Hello World!”,此内容是在 init module0函数中定义的,由此说明,helloworld 模块已经被成功装载到了内核中。
也可以使用1smod命令查看模块信息,如图所示。
#lsmod (2)当不需要使用helloworld 模块时,可以卸载这个模块。
# sudo rmmod helloworld
可以通过dmesg命令查看控制台的输出,如图所示
# dmesg
此时,可以看到输出结果“<1>Goodbye!”,此内容是在cleanup module0函数中定义的。由此说明,helloworld 模块已被删除。如果这时候再使用1smod命令,就会发现helloworld模块已经不存在了。
五、实验总结
1.总结并分析实验中出现的问题及对应的解决方法
本次实验和实验3相似,进行的比较顺利,并无出现太多问题,唯一需要注意的就是helloworld.c和Makefile文件的编写,不要出现错误,make需要在对应的文件夹中执行。
2.如何实现将多个源文件合并到一个内核模块中?
创建一个新的文件,命名为 "Makefile",用于编译和构建内核模块。
在 "Makefile" 文件中,定义模块的编译规则和依赖关系。可以使用变量来指定需要编译的源文件列表,如:obj-m := mymodule.o,其中 "mymodule.o" 是模块的目标文件名。
在同一个目录下创建多个源文件,如 "module1.c"、"module2.c" 等。
在每个源文件中,使用模块相关的宏(如 module_init 和 module_exit)定义模块的初始化和退出函数。
在 "Makefile" 文件中,通过变量指定需要编译的源文件列表,如:obj-m += module1.o module2.o,将所有需要编译的源文件都列出。
运行 make 命令编译内核模块,生成目标文件。
3.总结体会
本次实验进行了Linux内核模块的编写。
Linux内核非常庞大,包含很多组件,把需要的部分包含在内核中通常有两种办法:
1)把所有需要的功能都编译进内核中。
但是生成的内核会非常大;为现有内核添加、删除功能,需要重新编译。
2)不包含所有功能,需要的时候,动态地加载代码到内核。
这种机制即为模块(Module)。
一个Linux内核模块主要组成如下:
1)模块加载函数
如前面通过宏定义module_init声明的hello_init,就是模块加载函数。当通过insmod或modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作。
实验中对应init_module()函数。
2)模块卸载函数
如前面通过module_exit声明的hello_exit。当通过rmmod命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能。
实验中对应cleanup_module()函数。
3)模块许可证声明
通过MODULE_LICENSE许可证声明描述内核的许可权限,如不声明LICENSE,模块被加载时,将收到内核被污染(Kernel Tainted)的警告。可接受LICENSE:"GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MPL/GPL", "Proprietary"。推荐使用"GPL"或"GPL v2"。
实验中对应MODULE_LICENSE(“GPL”)。
4)模块参数(可选)
模块参数是模块被加载时,可以传递给它的值。本身对应模块内部的全局变量。
5)模块导出符号(可选)
内核模块可以导出的符号(symbol,对应于函数或变量),若导出,其他模块则可以使用本模块的变量或函数。
6)模块作者等信息声明(可选)
在实验过程中使用了许多指令和函数等等。
printk是内核模块输出函数,运行在内核空间;printf是glibc库函数,运行在用户空间。
printk可定义输出级别,printf不支持输出级别定义。
lsmod命令列出已加载模块信息,实际是读取、分析"/proc/modules",可以用cat命令输出已加载模块信息。
本次实验,我理解了针对Linux提出内核模块这种机制的意义,掌握Linux实现内核模块机制的基本技术路线。学习了运用Linux提供的工具和命令,掌握操作内核模块的方法。