在Linux种有一个很好的特性:内核提供的特性可在运行时拓展。
这就意味着当系统启动并运行时,我们可以向内核添加功能,当然也可以移除功能。可在运行时添加到内核中的代码称为"模块"。每个模块由目标代码组成,可以使用insmod程序将模块连接到正在运行的内核,也可以使用rmmod程序移除连接。
一个简单的例程:
#include <linux/init.h>
#include <linux/module.h>
static int __init hello_init(void)
{
printk(KERN_ALERT "Hello World !");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel World !");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
- 这个模块定义了两个函数,其中一个是在模块加载时被调用(hello_init),另一个是在模块卸载时被调用(hello_exit)。
- module_init() 和 module_exit(),两特殊的宏表述加载和卸载两函数。
- MODULE_LICENSE 这个是申明该模块采用自由许可证,如果未如此声明,会引起不必要的麻烦。
- 函数printk是内核定义的函数,类似标准c库的printf,在内核运行中不能使用c库,所以内核需要自己单独的打印函数。代码中的 KERN_ALERT 字符串是表示打印级别。
编译模块
第一步,首先,需要确保具备正确的版本编译器、模块工具、和其他的必要的工具。
1、内核源码,干净的内核源码可以在官网下载,或者可以访问国内的镜像网站,比如网易镜像站The Linux Kernel Archiveshttps://www.kernel.org/
Index of /kernel/http://mirrors.163.com/kernel/2、编译工具,编译工取决于运行环境(arm、x86),或由厂商定制。
第二步,是配置及编译内核,使其运行环境保持一致;以linux-3.18.24内核版本,使用arm-histbv310-linux-交叉编译工具链为例:
配置内核方法,在内核根目录下执行make menuconfig,或者直接指定配置文件
make -C <内核源码路径> ARCH=arm CROSS_COMPILE=arm-histbv310-linux- <指定的配置文件>
注:使用的是Android环境,所以习惯使用"-C"项,亦可在内核源码直接执行。
最终会在源码根目录下生成一个隐藏文件".config",执行make进行编译
make -C linux-3.18.y/ ARCH=arm CROSS_COMPILE=arm-histbv310-linux- -j 4 uImage
第三步,编写Makefile
KERNELDIR ?= /home/dengcaixiang/other/linux-3.18.y
ARCH ?= arm
CROSS_COMPILE ?= arm-histbv310-linux-
PWD := $(shell pwd)
obj-m += hello.o
.PHONY: all clean
all:
make -C $(KERNELDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules V=1
clean:
make -C $(KERNELDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean
第四步,编写好Makefile后,执行make,最终会生成一个动态模块hello.ko,在此过程中,可能会遇到各种报错,一个一个解决即可
运行模块
可通过insmod将模块加载到正在运行的内核中,lsmod可以查看模块,rmmod可以卸载模块,运行结果如下:
至此简单的一个内核模块就完成了。