linux 内核学习10-从第一个内核模块开始
1. 准备工作
- c文件
#include <linux/init.h>
#include <linux/module.h>
// 该内核模块初始化函数 可以通过insmod命令来加载一个内核模块
static int __init my_test_init(void){
printk("my first kernel module init\n");
return 0;
}
// 该内核模块退出函数 ,可以使用rmmod命令卸载一个内核模块
static void __exit my_test_exit(void){
printk("goodbye\n");
}
//内核入口 my_test_init()
module_init(my_test_init);
//内核出口 这个模块的退出函数时my_test-exit()
module_exit(my_test_exit);
// 使用接受的软件许可协议
MODULE_LICENSE("GPL");
// 描述模块的作者信息
MODULE_AUTHOR("xiao");
// 简单描述该模块的用途或者功能
MODULE_DESCRIPTION("MY TEST KERNEL MODULE");
//为用户控件提供一个合适的别名
MODULE_ALIAS("mytest");
- makefile文件
1 BASEINCLUDE ?=/lib/modules/`uname -r`/build
2
3 mytest-objs :=my_test.o
4 obj-m :=mytest.o
5
6 all :
7 $(MAKE) -C $(BASEINCLUDE) M=$(PWD) modules;
8 clean:
9 $(MAKE) -C $(BASEINCLUDE) SUBDIRS=$(PWD) clean;
10 rm -f *.ko;
第三行
<模块名>-objs :=<目标文件>.o
第四行
obj-m :=<模块名>.o
第6-7行表示要编译执行的动作。
第8-10行表示执行make clean 需要的动作
接着输入make命令来编译
$ make
- 查看内核信息
$ uname -r
5.0.0-25-generic
$ cd /lib/modules/4.15.0-58-generic
$ ls -l
total 5300
drwxr-xr-x 2 root root 4096 Aug 6 03:45 initrd
drwxr-xr-x 16 root root 4096 Aug 21 02:36 kernel
-rw-r--r-- 1 root root 1269888 Aug 21 02:36 modules.alias
-rw-r--r-- 1 root root 1250246 Aug 21 02:36 modules.alias.bin
-rw-r--r-- 1 root root 7629 Aug 6 03:45 modules.builtin
-rw-r--r-- 1 root root 9685 Aug 21 02:36 modules.builtin.bin
-rw-r--r-- 1 root root 551723 Aug 21 02:36 modules.dep
-rw-r--r-- 1 root root 780064 Aug 21 02:36 modules.dep.bin
-rw-r--r-- 1 root root 317 Aug 21 02:36 modules.devname
-rw-r--r-- 1 root root 206075 Aug 6 03:45 modules.order
-rw-r--r-- 1 root root 540 Aug 21 02:36 modules.softdep
-rw-r--r-- 1 root root 590768 Aug 21 02:36 modules.symbols
-rw-r--r-- 1 root root 720722 Aug 21 02:36 modules.symbols.bin
drwxr-xr-x 3 root root 4096 Aug 21 02:36 vdso
- 编译之后的结果
$ ls
Makefile Module.symvers mytest.ko mytest.mod.o mytest.o
modules.order my_test.c mytest.mod.c my_test.o
可以通过file命令来检查编译的模块是否正确。可以看到编程x86-64架构的ELF文件,已经成功了
$ file mytest.ko
mytest.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=eb0017daac8924d6450529c21430501d0cbefa7e, not stripped
也可以通过modinfo
进一步检查
$ modinfo mytest.ko
filename: /home/groot/test/mytest.ko
alias: mytest
description: MY TEST KERNEL MODULE
author: xiao
license: GPL
srcversion: C4ABC60E9EB1421D8527091
depends:
retpoline: Y
name: mytest
vermagic: 5.0.0-25-generic SMP mod_unload
- 验证模块
$ sudo insmod mytest.ko
$dmesg |grep first
查看内核打印日志
[39568.716952] my first kernel module init
也可以使用lsmod
命令查看当前的mytest模块是否已经被加载到系统中
lsmod
Module Size Used by
mytest 16384 0 //这个就是自定义摸模块
加载模块之后,系统会在sys/modules
目录下新建一个目录,比如对于mytest模块会建一个名为mytest的目录
$ sudo tree -a
.
├── coresize
├── holders
├── initsize
├── initstate
├── notes
│ └── .note.gnu.build-id
├── refcnt
├── sections
│ ├── .exit.text
│ ├── .gnu.linkonce.this_module
│ ├── .init.text
│ ├── __mcount_loc
│ ├── .note.gnu.build-id
│ ├── .note.Linux
│ ├── .rodata.str1.1
│ ├── .strtab
│ └── .symtab
├── srcversion
├── taint
└── uevent
3 directories, 17 files
- 卸载模块
$ sudo rmmod mytest.ko
3. 总结
- 模块加载函数:加载模块时,该函数会先自动执行,通常做一些初始化工作。
- 模块卸载函数:卸载模块时,该函数也会被自动执行,执行一些清理工作。
- 木块许可声明:内核模块必须声明许可证,否则内核会发出被污染警告。
- 模块参数:根据需求来添加,为可选项
- 模块作者和描述声明:一般都需要完善这些信息
- 模块导出符号:根据需求来添加,为可选项
4.其他
这里的操作流程参考的是奔跑吧linux内核入门篇。大家想学习linux内核,可以去买奔跑吧linux内核 入门篇和奔跑吧linux内核。
这里给到作者笨叔叔的学习资料 github地址 这里有笨叔叔调教好的linux内核。这来有他的视频教程 视频地址 内核地址