我是靠谱客的博主 平常信封,最近开发中收集的这篇文章主要介绍linux内核模块中 不包括,初学Linux内核模块及各种总结(有助于初学者使用),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

(1)什么是Linux内核模块

首先什么是内核模块呢?这对于初学者无非是个非常难以理解的概念。内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),我们简称为模块。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kernel)。单内核的最大优点是效率高,因为所有的内容都集成在一起,但其缺点是可扩展性和可维护性相对较差,模块机制就是为了弥补这一缺陷。

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

总之,模块是一个为内核(从某种意义上来说,内核也是一个模块)或其他内核模块提供使用功能的代码块。

(2)内核模块的优缺点

利用内核模块的动态装载性具有如下优点:

·将内核映象的尺寸保持在最小,并具有最大的灵活性;

·便于检验新的内核代码,而不需重新编译内核并重新引导。

但是,内核模块的引入也带来了如下问题:

·对系统性能和内存利用有负面影响;

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

·为了使内核模块访问所有内核资源,内核必须维护符号表,并在装入和卸载模块时修改这些符号表;

·有些模块要求利用其他模块的功能,因此,内核要维护模块之间的依赖性。

·内核必须能够在卸载模块时通知模块,并且要释放分配给模块的内存和中断等资源;

·内核版本和模块版本的不兼容,也可能导致系统崩溃,因此,严格的版本检查是必需的。

尽管内核模块的引入同时也带来不少问题,但是模块机制确实是扩充内核功能一种行之有效的方法,也是在内核级进行编程的有效途径。

(3)编写一个简单的模块

Helloworld是计算机史上的经典,每次我们接触一个新的东西总是用的上它!同样,在这里我也用Helloworld做例子:

/**

*  This is a simple example of modules.

*

* Compile:

*   Save this file name it helloworld.c

*   # echo "obj-m := helloworld.o" > Makefile

*   # make -Wall -C /lib/modules/`uname -r`/build M=`pwd` modules

* Load the module:

*   #insmod helloworld.ko

*/

#include 

#include 

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)

{

printk(KERN_ALERT "Hello, Worldn");

return 0;

}

static void hello_exit(void)

{

printk(KERN_ALERT "Goodbye ,cruel worldn");

}

module_init(hello_init);

module_exit(hello_exit);

对于头文件:

所有模块都要使用头文件module.h,此文件必须包含进来。

头文件kernel.h包含了常用的内核函数。

头文件init.h包含了宏_init和_exit,它们允许释放内核占用的内存。

编写内核模块时必须要有的两个函数 :

1> 加载 函数:

static int init_fun(void)                                   |   static int __init init_fun(void)

{                                                                     |   {

// 初始化代码                                                 |    //初始化代码

}                                                                     |   }

2> 卸载函数( 无返回值 )

static void cleaup_fun(void)                          |   static void __exit cleaup_fun(void)

{                                                                    |   {

// 释放代码                                                    |    //释放代码

}                                                                    |   }

_init 和 __exit 是 Linux 内核的一个宏定义,使系统在初始化完成后释放该函数,并释放其所占内存。因此它的优点是显而易见的。所以建议大家啊在编写入口函数和出口函数时采用后面的方法。

1> 在 linux 内核中,所有标示为 __init 的函数在连接的时候都放在 .init.text 这个区段内,此外,所有的 __init 函数在区段 .initcall.init 中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些 __init 函数,并在初始化完成后释放 init 区段(包括 .init.text,.initcall.init 等)。

2> 和 __init 一样, __exit 也可以使对应函数在运行完成后自动回收内存。

还有,我们在内核 编程时所用的库函数和在用户态下的是不一样的。如程序中使用的printk函数,对应于用户态下的printf函数,printk 是内核态信息打印函数,功能和printf类似但 printk还有信息打印级别。

加载模块和卸载模块:

1>module_init(hello_init)

a. 告诉内核你编写模块程序从那里开始执行。

b.module_init() 函数中的参数就是注册函数的函数名。

2>module_exit(hello_exit)

a. 告诉内核你编写模块程序从那里离开。

b.module_exit() 中的参数名就是卸载函数的函数名。

编译运行:

编译的方法我在代码中使用注释已经说明!

首先我们保存代码到helloworld.c,如果使用vim helloworld.c更好,直接wq保存退出即可!

第二步是写一个Makefile文件,Makefile文件所做的工作是编译生成helloworld.o,helloworld.ko等文件!

什么是 Makefile , make?

1>Makefile 是一种脚本,这种脚本主要是用于多文件的编译

2> make 程序可以维护具有相互依赖性的源文件,但某些文件发生改变时,它能自动识别出,并只对相应文件进行自动编译。

上述简单例子中的Makefile文件的内容为:obj-m:=helloworld.o,在这我要提醒大家,在网上有许多种Makefile文件的写法,但都太麻烦了,如果写的是内核模块,obj-m:=*.o足矣(*是你的模块文件名,比如上面的hellworld.c文件).

之后使用make -Wall -C /lib/modules/`uname -r`/build M=`pwd` modules命令生成helloworld.o,helloworld.ko等文件,细心的朋友可以看到有的人直接使用 make

-C /lib/modules/`uname -r`/build M=`pwd` modules,中间省略了-Wall,那么什么是 -Wall呢?Wall可以看成 W+all,而W代表Warning,所以使用 -Wall

即是显示所有警告!

最后一步则是insmod   helloworld.ko,即是加载helloworld模块!卸载模块的命令是rmmod  helloworld.ko

下面是在运行时容易遇到的几个问题:

1)Makefile的第一个字母没有大写,写成了makefile,这是根本性错误,如果没有发现,程序没法运行。

2)make -C /lib/modules/`uname -r`/build M='pwd' modules中运行pwd指令的两边是单引号'pwd',正确用法应该是``!

注:` `内放的是命令,说简单点就相当与函数中嵌套函数的意思 ! 比如pwd则是显示当前目录的命令,在此处你也可以将`pwd`换成当前helloworld.c的所在目录!

而  uname  -r 是显示当前内核版本的命令,比如我使用的是 3.2.0-26-generic,我也可以直接在`uname -r`的位置写上3.2.0-26-generic!

3)使用上述make命令生成helloworld.ko 一般我们需要Ctrl+Alt+F1进入控制台运行(Linux给我们提供了6个控制台,所以按住Ctrl+Alt+F1~F6都可以)之后如果需要进入图形界面只需要Ctrl+Alt+F7就可返回。

我当时在运行insmod helloworld.ko时出错,错误提示为“insmod: error inserting 'helloworld.ko': -1 Operation not permitted”。后来使用sudo insmod helloworld.ko,然后输入用户密码才可正常运行,可能出错原因是权限不够,因为我使用的Ubuntu,这是个很常见的错误。当程序正常运行时,当我们输入 dmesg 时就可以看到程序运行的结果了。

使用lsmod | grep hellodworld --color可查看模块是否已載入,lsmod即是list  modules的简写,意思是列出所有已载入的模块,后面的grep hellodworld的意思是匹配hellodworld字段并--color标记颜色!

对于上述.ko文件等,我在这里补充一下 Linux下后缀名为ko、o、a、so、la的文件简述:

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

2).o 是相当于windows中的.obj文件

注意:.ko与.o的区别在于,.ko是linux 2.6内核编译之后生成的,多了一些module信息,如author,license之类的。.o文件则是linux 2.4内核编译生成的。

3).a 是静态库,由多个.o组成在一起(assemble 集合),用于静态连接

4).so 是shared object的缩写,用于动态连接,和windows的dll差不多

5).la 为libtool自动生成的一些共享库。

龙哥教导:在遇到问题时不能一味的上网找解决方法,首先应该自己试一试能否解决。

最后

以上就是平常信封为你收集整理的linux内核模块中 不包括,初学Linux内核模块及各种总结(有助于初学者使用)的全部内容,希望文章能够帮你解决linux内核模块中 不包括,初学Linux内核模块及各种总结(有助于初学者使用)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部