Makefile
obj-m:=kstack.o
KDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *symvers *Module.markers
第一次编内核ko,用这个makefile试了一下
关键代码解说
- obj-m := <模块名>.o
obj-m是kbuild makefile中用来做目标定义的,obj-m是指编译成模块,亦即生成ko文件。
obj-m:=kstack.o—->这里面kstack.o是需要变化的,通常而言和源代码的文件同名即可,比如我的c代码是kstack.c,所以这里就是kstack.o,编出来就是kstack.ko。
- <模块名>-objs := <目标文件>
但是有时候,ko是由kstack.o file1.o file2.o这样多个.o文件编译成kstack.ko模块,那需要:
obj-m := kstack.o
kstack-objs := file1.o file2.o kstack_main.o(注意,这里不要用kstack.o)
所以<模块名>-objs用在多.o文件编译的时候,这个变量是说明生成模块kstack.ko需要的目标文件。
- KDIR
KDIR:=/lib/modules/$(shell uname -r)/build
这是我们正在运行的操作系统内核编译目录。也就是编译模块需要的环境。
uname -r可以查看当前系统使用的内核版本以及子版本号。
- M=
指定我们源文件的位置
下面我们写一个程序来试一下,这个程序会在被加载时打印进程名。
源程序:kstack.c
#include <linux/init.h>
#include <linux/module.h>
#include <asm/thread_info.h>
#include <linux/sched.h>
static int test_init(void)
{
int i = 0;
struct thread_info *p = NULL;
struct task_struct *t = NULL;
p = (struct thread_info *)((unsigned long)&i & ~0x1fff);
t = p->task;
printk("Process name is ---->%s\n",t->comm);
return 0;
}
static void test_exit(void)
{
printk("---Remove---\n");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("WSK");
在源文件路径下执行make命令,我们得到了kstack.ko的文件
然后测试一下效果
我们可以看到,printk打印的关键字已经出现在dmesg的内核日志里了。