草庐IT

[Linux驱动开发一]最简单的内核模块

TD祥 2023-07-17 原文

目录

一、预备知识

1.1 什么是内核模块?

1.2 Linux内核模块组成部分

二、源码编写

1.1 hello.c源码编写

1.2 Makefile编写

三、源码编译

3.1 make编译

3.2 insmod加载内核模块

3.3 rmmod移除内核模块

3.4 查看内核模块

3.4.1 lsmod命令

3.4.2 cat /proc/modules

3.4.3 ls /sys/module/hello/

3.5 dmesg查看模块输出

 四、小结


相关代码下载链接

一、预备知识

1.1 什么是内核模块?

        Linux 内核模块(LKM)是一些在启动的操作系统内核需要时可以载入内核执行的代码块,不

需要时由操作系统卸载。它们扩展了操作系统内核功能却不需要重新编译内核、启动系统。如果没

有内核模块,就不得不反复编译生成操作系统的内核镜像来加入新功能,当附加的功能很多时,还

会使内核变得臃肿。

1.2 Linux内核模块组成部分

        (1) 模块加载函数(必须):当通过insmod 或modprobe 命令加载内核模块时,模块的加载函

数会自动被内核执行,完成本模块相关初始化工作。

        (2) 模块卸载函数(必须):当通过rmmod 命令卸载模块时,模块的卸载函数会自动被内核执

行,完成与模块加载函数相反的功能。

        (3) 模块许可证声明(必须):模块许可证(LICENCE)声明描述内核模块的许可权限,如果

不声明LICENCE,模块被加载时将收到内核被污染的警告。大多数情况下,内核模块应遵循GPL 兼

容许可权。

        (4) 模块参数(可选):模块参数是模块被加载的时候可以被传递给他的值,它本身对应模块内部

的全局变量。

        (5) 模块导出符号(可选):内核模块可以导出符号(symbol,对应于函数或变量),这样其他模

块可以使用本模块中的变量或函数。

        (6) 模块作者等信息声明(可选

        一个内核模块至少初始化函数init_module()和结束函数cleanup_module()。两个函数可以起任

意的名字,通过宏module_init()和module_exit()注册调用要编译内核模块,把代码嵌进内核空间。

二、源码编写

        本节所提供示例十分简单,仅仅实现了在内核加载时打印“HELLO LINUX MODULE”,在内核

卸载时打印“GOODBYE LINUX MODULE”。

1.1 hello.c源码编写

/* 内核模块必须包含的头文件 */
#include<linux/module.h>

/* 加载函数:__init表示该函数只能在初始化期间使用,模块装载完后内核就会空间回收,释放内存*/
static int __init hello_init(void){
    printk(KERN_INFO "HELLO LINUX MODULE\n");
    return 0;
}

/* 卸载函数 */
static void __exit hello_exit(void){
    printk(KERN_INFO "GOODBYE LINUX MODULE\n");
}

/* 宏:指明初始化函数和清除函数 */
module_init(hello_init);
module_exit(hello_exit);

/* 描述性定义*/
MODULE_LICENSE("Dual BSD/GPL");  /* 许可协议 */
MODULE_AUTHOR("XZX");  /* 作者 */
MODULE_VERSION("V1.0")  /* 版本号 */

1.2 Makefile编写

# 定义内核源码的目录
KERNELDIR ?=/lib/modules/$(shell uname -r)/build
# 定义当前目录
PWD        := $(shell pwd)
# 要生成的内核模块
obj-m := hello.o

all:
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mode.c .tmp_versions *.mod *.order *.symvers

1.2 Makefile编写

三、源码编译

3.1 make编译

3.2 insmod加载内核模块

        我们可以通过"sudo insmod hello.ko"加载内核模块,并通过lsmod查看

 

 

3.3 rmmod移除内核模块

        通过“sudo rmmod hello”命令移除hello模块。如下图所示,此时列表中不再存在hello模块

3.4 查看内核模块

3.4.1 lsmod命令

 

3.4.2 cat /proc/modules

3.4.3 ls /sys/module/hello/

3.5 dmesg查看模块输出

 四、小结

        本节主要帮助大家了解基本的Linux内核模块开发框架和编译方法,掌握Linux内核模块添加流

程,理解了Linux内核模块代码中的一些常见宏和参数。

有关[Linux驱动开发一]最简单的内核模块的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  6. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  7. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  8. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  9. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  10. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

随机推荐