# linux 内核学习10-从第一个内核模块开始

linux 内核学习10-从第一个内核模块开始

1. 准备工作

  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");
  1. 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
  1. 查看内核信息
$ 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

  1. 编译之后的结果
$ 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 

  1. 验证模块
$ 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
  1. 卸载模块
$ sudo  rmmod mytest.ko

3. 总结

  1. 模块加载函数:加载模块时,该函数会先自动执行,通常做一些初始化工作。
  2. 模块卸载函数:卸载模块时,该函数也会被自动执行,执行一些清理工作。
  3. 木块许可声明:内核模块必须声明许可证,否则内核会发出被污染警告。
  4. 模块参数:根据需求来添加,为可选项
  5. 模块作者和描述声明:一般都需要完善这些信息
  6. 模块导出符号:根据需求来添加,为可选项

4.其他

这里的操作流程参考的是奔跑吧linux内核入门篇。大家想学习linux内核,可以去买奔跑吧linux内核 入门篇和奔跑吧linux内核。
这里给到作者笨叔叔的学习资料 github地址 这里有笨叔叔调教好的linux内核。这来有他的视频教程 视频地址 内核地址

上一篇:2019年8月30日


下一篇:linux--杂项