系统环境
RHEL6
内核版本:
创建内核源代码目录
linux内核源码下载地址:
http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/
官网:
www.kernel.org
注意:下一个和你当前运行版本一样的内核,这里可以看到我当前运行的内核版本是2.6.32-279.el6.x86_64,好,那我就下一个2.6.32.x的版本(必须有和当前运行的版本有同样的版本号,否则在加载模块时候insmod: error inserting ‘***.o’ :-l invalid module format这样的错误)。
下载的文件放在 /usr/src 目录下
解压
tar -zxvf linux-2.6.32.tar.gz
解压后生成linux-2.6.32的目录,进入目录
配置.config文件
make oldconfig
中间过程回车采用默认值
编译内核
make bzImage (此处i要大写,编译压缩形式的内核)
make modules (编译选择的模块)
也可直接make
make (2.6内核 make = make bzImage + make modules)
然后将编译后的模块转移到系统标准位置,模块在系统中的标准目录位于/lib/modules/x.y.z,后面的x.y.z是版本号,为安全起见,在运行#make modules-install之前最好对/lib/modules进行备份。模块通常是带有扩展名.o的文件,使用命令#lsmod可以对当前内核的模块进行列表。
make modules_install
安装内核:
make install
此时产生了错误:ERROR: modinfo: could not find module nf_defrag_ipv6
还有几个错是vm开头的错误,
这几个错误不影响使用,vm的错误可能影响VMTools的使用。
重启,开启时选择新安装的内核:Linux-2.6.32
编写hello模块
vim hello.c
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_EMERG "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG"Goodbye, world\n");
}
module_init(hello_init);
module_exit(hello_exit);
同时编写Makefile,在同一目录下:
vim Makefile
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KDIR := /lib/modules/2.6.32/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
注意:其中KDIR指明了引用头文件的位置,应根据具体情况修改该文件。ifneq是比较两个参数是否相同。
ifneq ($(KERNELRELEASE),)
第二个参数空就是NULL
意思是 $(KERNELRELEASE), 的值不是NULL就可以进行下面的编译处理
(切记:Makefile每个命令的第一个字符必须是制表符[tab]即KDIR,make,rm前不是四个空格空格开头而是一个[tab],不要想当然的随便认为只是个空格。否则会在编译是报出***missing seperater .stop. 的错误 )
在当前路径执行make
make
执行后产生hello.ko文件
加载模块:
insmod hello.ko
如果你遇到insmod: error inserting ‘hello.o’ :-l invalid module format这样的错误,不用惊慌,并不是你的模块有问题,而是你当前运行的内核版本与你编译链接的头文件版本不一致,所以会出现格式不对的问题。此时,你可以更换系统内核(即最后的安装内核 make install 并重启切换内核操作),也可以下载一个与系统版本一致的内核源码重新编译该模块。如果你没有遇到任何问题,也没有打印出任何信息,那么恭喜你,你的内核加载成功了,你可以使用lsmod命令来罗列出当前你系统加载的所有模块,相信你在列表中会找到hello的。你可能会疑惑,为什么没有如我们想像中的那样,打印出"Hello, World"?呵呵,这是因为printk并不会把打印内容打印到你当面的终端,要知道模块是运行在内核态的,而你所能面对的是用户态,内核态的打印信息需要通过log或者dmesg命令来查看,想看到打印結果,最简单的方法是敲入dmesg命令,你就可以看到你所希望看到的信息了
最后,使用rmmod hello.ko来卸载模块,同样,使用dmesg可以看到打印出的"Goodbye, World"。
rmmod hello.ko
dmesg | tail -2