内核模块编程---hello world

什么是内核模块?

其全称为动态可加载内核模块。之所以提供模块机制,是因为Linux是“单块内核”的操作系统,单内核的最大优点是效率高,因为所有的内容都集中在一起,但其缺点是可扩展性和可维护性相对较差,模块机制就是为了弥补这一缺陷。Linux内核是模块化组成的,它允许我们方便地在运行时动态地向内核中插入或从中删除代码。

模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时加载,被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。

特点:

装入的内核模块和其他内核部分完全一样,具有相同的访问权限,因此,差的内核模块会导致系统崩溃;

模块编程和内核版本密切相连,内核版本和模块版本的不兼容,也可能导致系统崩溃;

这些代码被一并组合在一个单独的二进制镜像中,这样基本内核镜像就尽可能的小,而且灵活性很好否则,在需要添加新硬件或者升级设备驱动时,必须重新构建内核。

用户层编程和内核模块编程的区别

选项应用程序内核模块程序
使用函数libc 库内核函数
运行空间用户空间内核空间
运行权限普通用户超级用户
入口函数libc 库内核函数
运行空间main()module_init
出口函数exit()module_exit
编译gccmakefile
链接gccinsmod
运行直接运行insmod
入口函数libc 库内核函数
调试gdbkdbug 、 kdb 、 kgdb

下面编写简单的内核模块

还是从最经典的hello world写起。

/*************************************************************************
        > File Name: hello.c
        > Author: Tanswer_
        > Mail: 98duxm@gmail.com
        > Created Time: 2017年02月27日 星期一 10时53分58秒
 ************************************************************************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk("hello world\n");
    return 0;
}

static void hello_exit(void)
{
    printk("Goodbye world\n");
}

module_init(hello_init);
module_exit(hello_exit);
简单来看看代码

语法和我们平时写的C代码差异比较大,我也还没有适应,有机会再继续写。必要的两个函数:加载函数和卸载函数,分别还有另一种写法。printk是内核态下的打印函数。还可以加模块的声明与描述,比如:MODULE_AUTHOR("Tanswer");//作者。我们详细看一下头文件,在编译前需要配一下环境。

头文件
 #include <linux/module.h>  所有模块都要使用的
 #include <linux/kernel.h>  包含了常用的内核函数
 #include <linux/init.h>    包含了宏_init和_exit,它们允许释放内核占用的内存

内核头文件的位置:/usr/src/kernels/
用户层头文件的位置:/usr/include

我进入/usr/src/后发现里面是空的,并没有源码树,所以执行 #yum install kernel-devel 安装源码树。安装完成后,我发现我的uname -r 和 源码树目录显示的内核版本号不一致
这里写图片描述

这就导致了我写的Makefile出现了问题,见下面代码。

Makefile
obj-m := hello.o

CURRENT_PATH:=$(shell pwd)
KERNEL_NUM:= $(shell uname -r)
#KERNEL_PATH:=/usr/src/kernels/$(KERNEL_NUM)
KERNEL_PATH:=/usr/src/kernels/3.10.0-514.6.2.el7.x86_64

all:
#        make -C $(KERNEL_PATH) M=$(CURRENT_DIR) modules
        make -C $(KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
        make -C $(KERNEL_PATH) M=$(CURRENT_PATH) clean

第一次我写的是注释掉的那句,结果make 的时候显示路径名不正确,上面的原因我还不知道,懂得请赐教。所以我直接将路径名写上去了,就是现在的那句。我再次make,看下图:

这里写图片描述

又出现了两个错误,我逐个解决,上面那个错误,提示说please install libelf-dev or elfutils-libelf-devel 那我就乖乖听话装上它,然后我再次make:

这里写图片描述

上面那个错误已经解决,剩下这个以前用makefile的时候也没遇到过,我google了一下,发现有提这个问题的,但是没有解决方法。我没办法,有点失望就随手点开Makefile来看,然后……我就发现了一个小错误。。。Makefile代码中 -C 后指定的是 Linux 内核源代码的目录,而 M= 后指定的是 hello.c 和 Makefile 所在的目录,但是我第一次写成了CURRENT_DIR,就是我注释掉的那句,可明明我定义的变量是CURRENT_PATH,然后我就改过来了。再次make,终于终于终于

这里写图片描述

编译正确。
这里写图片描述

补充(转):
.ko 是kernel object 的缩写,是Linux 2.6内核使用的动态连接文件,在Linux系统启动时加载内核模块

链接和运行
1.insmod hello.ko  加载模块
2.dmesg            查看结果
3.rmmod            卸载模块

补充:常用的模块编程命令

1.lsmod命令查看系统中加载了的所有模块以及模块间的依赖关系
2.cat /proc/modules来查看加载模块信息
3.内核中已加载模块的信息也存在于 /sys/module 目录下,加载 hello.ko 后,内核中将包含 /sys/module/hello 目录,该目录下又包含一个 refcnt 文件和一个 sections 目录,在 /sys/module/hello 目录下运行 tree -a 可以看到他们之间的关系
4.使用 modinfo < 模块名 > 命令可以获得模块的信息,包括模块的作者,模块的说明,某块所支持的参数以及 vermagic

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值