linux module 模块编程

转载自:http://blog.csdn.net/eroswang/archive/2008/09/13/2924875.aspx

摘要
Linux内核模块编程的资料有些纷繁复杂,有的过于简单,有的过于庞杂,我试图用笔记的形式想读者展示怎样来进程Linux模块编程,力图做到简明扼要,这篇文章也是作为本人备忘的资料,所以有些地方过于简略是难免的。本来这篇文章的目的就是让用户知其然,至于所以然还是请参考相应的资料,其实最好的资料莫过于Linux Kernel Source。

适用范围:

Linux Kernel >= 2.6.0

Linux模块简介
首先这个module不同于microkernel的module,microkernel的module是一个个的daemon进程,工作于用户空间,Linux的module只是一个内核的目标代码,内核通过执行运行时的连接,来把它整合到kernel中去,所以说Linux的module机制并没有改变Linux内核为monolithic OS本质,其module也是工作于内核模式,享有内核的所有特权。

至于为什么要引入Linux Kernle Module(一下简称LKM),我想至少有一下几点:

模块化编程的需要,降低开发和维护成本。 
增强系统的灵活性,使得修改一些内核功能而不必重新编译内核和重启系统。 
降低内核编程的复杂性,使入门门槛降低。

相关宏及头文件
LKM需要包含以下头文件:<linux/kernel.h> <linux/module.h>

需要定义以下宏:__KERNEL__, MODULE

一个简单的内核模块示例

1/*file:   hello.c*/
 2
 3#ifndef __KERNEL__       
 4#define __KERNEL__
 5#endif
 6#ifndef MODULE       
 7#define MODULE
 8#endif
 9
10#include <linux/module.h>
11#include <linux/kernel.h>
12
13static int __init hello_init(void)
14{       
15    printk(KERN_ALERT "Hello, my LKM.\n");       
16    return 0;
17}
18
19static void __exit hello_exit(void)
20{       
21    printk(KERN_ALERT "Bye, my LKM.\n");
22}
23
24module_init(hello_init);
25module_exit(hello_exit);

很简答吧,不是吗?这个LKM的功能其实也很简单,就是当通过insmod加载它的时候,他打印Hello, my LKM.通过rmmod卸载它的时候他打印bye, my LKM.一个最基本的内核模块一般都包含有两个函数,一个是初始化函数(比如说这里的hello_init),一个是卸载函数(hello_exit), 当然也可以没有任何函数,只是提供一些变量。但是初始化函数和卸载函数必须成对出现。并且init函数当操作成功时返回值大于等于零,当操作失败时,返回非零。宏module_init和module_exit用于注册初始化函数和卸载函数。

LKM的编译
一个示例的Makefile如下所示

1obj-m := hello.o 
2KERNELBUILD := /lib/modules/`uname -r`/build
3default:        
4    make -C $(KERNELBUILD) M=$(shell pwd) modules
5clean:        
6    rm -rf *.o .*.cmd *.ko *.mod.c .tmp_versions

如果这个目录下面还有其它模块,只需要在hello.o后面添加就行了。

obj-m := hello.o mod.o在模块所在目录执行make,等成功后就可以得到我们想要的模块(hello.ko)了。

如果一个模块存在许多源文件,比如:hello, 由hello1.c hello2.c共同连接而成,需要在Makefile中加入如下行

hello-objs := hello1.o hello2.oLKM的加载
Linux为用户提供了modutils,用来操纵模块。这个工具集主要包括:

insmod 安装模块rmmod 删除模块modprobe 比较高级的加载和删除模块,可以解决模块之间的依赖性lsmod 列出已经加载的模块和其信息modinfo 用于查询模块的相关信息,比如作者,版权...试着用命令insmod hello.ko加载模块,rmmod删除模块,看看有什么事情发生了。你有可能看不见任何输出,难道是有错误发生?No,执行命令tail /var/log/message呵呵,是不是看到了?

Feb 19 00:07:35 gentux Hello, my LKM.Feb 19 00:07:38 gentux Bye, my LKM.模块其它信息
比较常用信息常常包括:作者、描述、版权等,为此LKM为我们提供了如下宏:

MODULE_AUTHOR("author");MODULE_DESCRIPTION("the description");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("dev"); // 设备驱动程序所支持的设备。比较常用的Free license有"GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MPL/GPL"。

模块参数
用户空间的应用程序可以接受用户的参数,LKM也可以做到,只是方式有些不同而已。相关的宏有:

MODULE_PARM(var, type);MODULE_PARM_DESC(var, "the description of the var");模块参数的类型(即MODULE_PARM中的type)有一下几种:

b byte(unsigned char) 
h short 
i int 
l long 
s string(char*) 
这些参数最好有默认值,如果有些必要参数用户没有设置可以通过在module_init指定的init函数返回负值来拒绝模块的加载。 LKM还支持数组类型的模块,如果在类型符号前加上数字n则表示最大程度为n的数组,用“-”隔开的数字分别代表最小和最大的数组长度。

示例:MODULE_PARM(var, "4i"); // 最大长度为4的整形数组MODULE_PARM(var, "2-6i"); // 最小长度为2,最大长度为6的整形数组如何用insmod传入参数,其实man一下就可以了,不过现在的man有些过于简单,所以在此说明一下:

insmod variable=value[,value2...] ...其中value可以用引号括起来,也可以不用。但是有一点“=”前后不能留有空格,并且value中也不能有空格。

模块符号的导出
和用户空间的应用程序不同的是,引入一个模块的目的常常是为了给内核提供一些routine,来完成特定的功能,很少有模块什么符号都不导出,为此Linux为用户提供了如下宏:

EXPORT_SYMBOL(var); // 输出symbol varEXPORT_SYMBOL_GPL(var); // 输出的symbol版权为GPL模块之间的依赖性
有的时候两个模块之间可能有依赖性,要加载的模块A,依赖于模块B,此时insmod是无能为力的,只能用modprobe来加载模块和其依赖的模块,否则只能手动一个个加载。

modprobe通过读取由depmod -a生成的/lib/modules/version/modules.dep来获得其所依赖的模块列表(也有可能是一个模块树),然后调用insmod来一个个按顺序加载。

命名空间的问题
对于不需要export的全局symbol最好用static进行修饰,限制其作用域为本文件,以防污染内核的命名空间。 
对于由内核或其它模块export的一些symbol,最好用extern进行修饰,以示其不在本文件。 
在可能用到errno变量的场合,因为内核没有export此symbol,只能有用户自行定义,比如:int errno; 
一个较复杂的模块示例

1/**//*file: hello.c*/
2#ifndef __KERNEL__
3#define __KERNEL__
4#endif
5#ifndef MODULE
6#define MODULE
7#endif
8#include <linux/module.h>
9#include <linux/kernel.h>
10MODULE_AUTHOR("xiaosuo <[email protected]>);
11MODULE_LICENSE(GPL);
12MODULE_DESCRIPTION("This module is a example.");
13static int int_var = 0;
14static const char *str_var = "default";
15static int int_array[6];
17MODULE_PARM(int_var, "i");
18MODULE_PARM_DESC(int_var, "A integer variable");
19MODULE_PARM(str_var, "s");
20MODULE_PARM_DESC(str_var, "A string variable");
21MODULE_PARM(int_array, "2-6i");
22MODULE_PARM_DESC(int_array, "A integer array");
24static int __init hello_init(void)
25{
int i;
printk(KERN_ALERT "Hello, my LKM.\n");
printk(KERN_ALERT "int_var %d.\n", int_var);
printk(KERN_ALERT "str_var %s.\n", str_var);
for(i = 0; i < 6; i ++)
{
printk("int_array[%d] = %d\n", i, int_array[i]);
}
return 0;
35}
37static void __exit hello_exit(void)
38{
printk(KERN_ALERT "Bye, my LKM.\n");
40}
42module_init(hello_init);
43module_exit(hello_exit);

时间: 2024-07-31 14:20:20

linux module 模块编程的相关文章

Linux模块编程框架

Linux模块编程框架 Linux是单内核系统,可通用计算平台的外围设备是频繁变化的,不可能将所有的(包括将来即将出现的)设备的驱动程序都一次性编译进内核,为了解决这个问题,Linux提出了可加载内核模块(Loadable Kernel Module,LKM)的概念,允许一个设备驱动通过模块加载的方式,在内核运行起来之后"融入"内核,加载进内核的模块和本身就编译进内核的模块一模一样.一个程序在编译的地址的相对关系就已经确定了,运行的时候只是进行简单的偏移,为了使模块加载进内核后能够被放

Linux - 模块编程初试

计算机网络的课程设计要做防火墙,老师没有限制在什么系统上面做,所以决定在Linux上实现.找了一下相关的资料,发现其实Linux有提供Netfilter/Iptables,为用户提供防火墙的功能,稍微看了一下,使用Iptables能够很方便地配置用户想要的防火墙,但是好像只能做过滤.数据报修改以及网络地址转换,好像不能做获取其中信息的功能,而且看了一下网上其他人的提问或者博客,好像想做类似的功能还是需要直接使用Netfilter.而如果想要使用Netfiler的话,需要编写hook函数,这个过程

简单实例讲解linux的module模块编译步骤(转)

注:原博文讲述较为详尽细致,故转到本地--aaronGao ------------------------------------------------------------------------------------------------------------------------------------------- 本文将直接了当的带你进入linux的模块编译.当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者能够看懂.之所以要写这篇文章,主要是因为从书本上学的话,

Linux内核驱动编程

Linux内核驱动编程 2015-02-12 驱动程序基础的东西这儿就不罗嗦了,百度上有更好的资料,此处我们只是注重实际用处. 下面我们开始写程序: 一.初步helloword程序 首先是来一个简单的hello. hello.c代码: 1 /****************************** 2 3 the first program 4 5 Hello World! 6 7 ******************************/ 8 9 #include <linux/mod

系统调用与模块编程

前言 转载请注明出处http://www.cnblogs.com/dvd0423/p/4183443.html 内核让人最爽的地方就是它给你站在山上看风景的感觉,一切尽收眼底.就像0号博文说的,不管它有没有用,知其所以然总是好的. 这个系列的内容围绕Linux内核展开,涉及的主要是我做KVM的过程中遇到的部分,网络.调度.KVM等等.虽然是底层的东西但是搞应用的人看一看也没有坏处.我们都知道内核太庞大,要想全了解几乎不可能,所以我们只能根据自己的需要去针对性的学习.而如此庞大的项目却能被组织的有

Linux下的编程实战【转】

一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台的),进程控制与进程通信编程 1.Linux进程 Linux进程在内存中包含三部分数据:代码段.堆栈段和数据段.代码段存放了程序的代码.代码段可以为机器中运行同一程序的数个 进程共享.堆栈段存放的是子程序(函数)的返回地址.子程序的参数及程序的局部变量.而数据段则存放程序的全局变量.常数以及动态数

Unix/Linux环境C编程入门教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建

1. openSUSE是一款优秀的linux. 2.选择默认虚拟机 3.选择稍后安装操作系统 4.选择linux  opensuse 5. 选择默认虚拟机名称 6.设置处理器为双核. 7.内存设置为2G 8. 选择网络地址转换 9.设置IO控制器 10. 选择默认磁盘类型 11.创建一个新的虚拟磁盘 12.设置磁盘大小 13.选择路径保存虚拟磁盘 14. 完成虚拟机创建 15.设置虚拟机 16.选择opensuse镜像 17.开启虚拟机 18.虚拟机启动 19.安装opensuse 20.安装程

Linux Security模块

一.Linux Security Modules Linux Security Modules (LSM) 是一种 Linux 内核子系统,旨在将内核以模块形式集成到各种安全模块中.在 2001 年的 Linux Kernel 峰会上,NSA 代表建议在 Linux 内核版本 2.5 中包含强制控制访问系统 Security-Enhanced Linux.然而,Linus Torvalds 拒绝了这一提议,因为 SELinux 并不是惟一一个用于增强 Linux 安全性的安全系统.除此之外,并不

kali linux Python 黑客编程1 开发环境初始化

kali linux Python 黑客编程1 开发环境初始化 为什么要选择Python? Python作为目前Linux系统下最流行的编程语言之一,对于安全工作者的作用可以和C++相提并论.Python提供了丰富的库供调用,丰富的第三方扩展模块.在网络应用,文本解析方面,Python编程有着其他语言无可比拟的优势.同时Python也是面向对象并且跨平台的语言,可以在linux/Unix.OSX.windows上无障碍运行. 1.1 查看PYTHON版本信息 Kali Linux默认已经安装了P