《linux内核设计与分析》内核模块编程

时间:2022-01-15 16:10:06

内核模块编程

一、准备工作

虚拟机:VMware Workstation 12
操作系统:ubuntu
当前内核版本:linux-headers-4.4.0-22-generic

二、有关于内核模块的知识

模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。

内核模块的相关指令:

查看内核版本

uname –a

模块编译好后,将模块放入内核

insmod 1.ko

查看程序的输出

dmesg

卸载模块

rmmod 1

 

三、编译形成新内核

根据学姐的代码:

Makefile

1 obj-m:=1.o
2 CURRENT_PATH:=$(shell pwd)
3 LINUX_KERNEL_PATH:=/usr/src/linux-headers-4.4.0-22-generic
4 all:
5 make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
6 clean:
7 make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

第1行:产生1模块的目标模块

第2行:模块所在的当前路径

第3行:LINUX_KERNEL_PATH后面要写你自己的内核版本对应的内核源码包地址。

make-C $(LINUX_KERNEL_PATH) 指明跳转到内核源码目录下读取那里的Makefile,M=$(CURRENT_PATH) 表明返回到当前目录继续执行当前的Makefile。

第5行:模块编译

第7行:清理

1.c

 1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/init.h>
4 #include <linux/sched.h>
5
6 static struct task_struct *pcurrent;
7 static int __init print_init(void)
8 {
9 printk(KERN_INFO "print current task info\n");
10 printk("pid\ttgid\tprio\tstate\n");
11 for_each_process(pcurrent){
12 printk("%d\t",pcurrent->pid);
13 printk("%d\t",pcurrent->tgid);
14 printk("%d\t",pcurrent->prio);
15 printk("%ld\n",pcurrent->state);
16 }
17 return 0;
18 }
19
20 static void __exit print_exit(void)
21 {
22 printk(KERN_INFO "Finished\n");
23 }
24 module_init(print_init);
25 module_exit(print_exit);

第1行:linux/kernel.h包含了常用的内核函数。

第2行:linux/module.h是必要的头文件,内核模块代码中必须包含。

第3行:linux/init.h含了宏_init和_exit,它们允许释放内核占用的内存。

第12行:Printk的功能类似于C语言中的printf,这个函数是由内核定义的。

先make生成1.ko文件等,在insmod 1.ko将模块放入内核,最后dmesg查看所编译程序的输出

《linux内核设计与分析》内核模块编程

四、遇到问题

在make这一步所遇到的基本所有问题都是因为.c文件出错所造成的。

还有一个问题就是在之前加载过模块之后再进行加载时会出现错误,这时将模块卸载了再进行加载就可以了。