linux内核编程--1模块的装载和卸载

1.   简介

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

也就是说:模块就是整个内核的一部分。但是跟C程序中函数不一样的一点是,内核模块可以在它所认为适当的时候,插入到内核或者从内核中删除,而且还不影响内核的正常运行。从而可以在必要的时候对内核进行裁剪,这样能够更好的适应于用户的需求。

2.   内核linux/module.h头文件

按照前文所述,内核linux/module.h头文件定义了模块安装/卸载的相关函数和宏定义,以下简述几个主要的函数和宏:

1)  module_init()函数

此函数以函数指针为参数,用于注册模块的初始化函数。相当于c程序可以在main函数之前注册初始化函数。此函数最终为调到__define_initcall函数,将函数指针加入.init段。当用insmod命令加载此模块时,会调用此函数。

#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn; \
LTO_REFERENCE_INITCALL(__initcall_##fn##id)

2)  module_exit()函数

此函数以函数指针作为参数,用于注册模块的退出(卸载)函数。相当于c程序可以用atexit()注册进程退出回调。当用rmmod命令卸载模块时,调用此函数。

3)  MODULE_LICENSE/ MODULE_AUTHOR/ MODULE_DESCRIPTION等

此大写MODULE_开头的几个符号为定义在linux/module.h头文件中解释模块信息的几个宏定义,分别代表:

MODULE_LICENSE--模块的license,有GPLBSD,即模块遵循的开源协议;

MODULE_AUTHOR--模块作者

MODULE_DESCRIPTION--模块描述

3.   模块代码

以老掉牙的hello world为例,编码如下模块代码如下,假设命令为:module_test.c。其中,printk函数为内核日志输出函数,可以打印内核日志信息。

//必要的头文件  
#include   
#include   
#include   
//模块许可证声明(必须)  
MODULE_LICENSE("Dual BSD/GPL");  
//模块加载函数(必须)  
static int hello_init(void)  
{
printk(KERN_ALERT "Hello World enter/n");  
return 0;  
}  
//模块卸载函数(必须)  
static void hello_exit(void)  
{  
    printk(KERN_ALERT "Hello World exit/n");     return;
}  
//模块的注册  
module_init(hello_init);  
module_exit(hello_exit);  
//声明模块的作者(可选)  
MODULE_AUTHOR("XXX");  
//声明模块的描述(可选)  
MODULE_DESCRIPTION("This is a simple example!/n");  
//声明模块的别名(可选)  
MODULE_ALIAS("A simplest example");  

4.   模块编译

编写完模块代码后,我们需要对其进行相关操作,变成一个内核模块文件(.ko文件)。也就需要写个Makefile文件,编译刚才的模块的代码。

obj-m += kernel_test.o  

#generate the path  
CURRENT_PATH:=$(shell pwd)

#the current kernel version number  
LINUX_KERNEL:=$(shell uname -r) 

#the absolute path--根据获取的内核版本拼装绝对路径
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)  

#complie object  
all:  
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
#clean  
clean:  
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean  

当make的目标为all时,-C $(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile

注意点:

1)      Makefile文件命名为:Makefile,第一个字符大写

2)      Makefile文件与源代码(.c)放在同级目录;

3)      以root权限执行make命令----root用户或普通用户+sudo。

5.   测试验证---装载/卸载模块

Linux提供insmod命令装载内核模块,rmmod命令卸载内核模块,相关的还有modinfo(显示模块的信息:模块作者、模块license等),lsmod(列出系统所有内核模块)。以下就测试模块的装载/卸载过程中printk打印的消息----用dmesg命令查看。-------------我的打印消息是:” Linux cai ji.------start----”、 “Linux caiji.------end”

linux内核编程--1模块的装载和卸载_第1张图片

6.   参考链接

http://blog.csdn.net/chang198932/article/details/17006537

你可能感兴趣的:(Linux,user,&,kernel)