话说Linux内核模块

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

首先,一个内核模块,就是一个ELF文件。

内核本身也是一个ELF文件。

一个模块,可能是一个协议,一个文件系统,一个驱动,一种具体的应用,等等任何东西。也可能是多种东西的组合。

内核在运行时,通过动态加载/卸载内核模块,可以动态扩展/删减内核的功能。


每个模块在编译时(假设模块名为xxx),会自动生成一个xxx.mod.c的文件,该文件会链接到xxx模块中去。

下面是此文件的一个示例:

#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
 .arch = MODULE_ARCH_INIT,
};

static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";


MODULE_INFO(srcversion, "0FE0F65AABA6F6A780CD6F7");

__this_module.init指向模块的初始化函数init_module,在模块被加载后,此函数即被内核调用。

__this_module.exit = cleanup_module指向模块的清理函数cleanup_module,在模块被卸载时,此函数即被内核调用。

模块通过如下方式声明初始化函数及清理。

module_init(xxx_init);

module_exit(xxx_exit);

这个__this_module.init中指向的函数名称不同,为什么呢?

来看看如下module_init及module_exit的定义就知道了。

可见,module_init及module_exit为传入的函数,分别定义了一个别名,即init_module和cleanup_module。

/* Each module must use one module_init(). */
#define module_init(initfn)					\
	static inline initcall_t __inittest(void)		\
	{ return initfn; }					\
	int init_module(void) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */
#define module_exit(exitfn)					\
	static inline exitcall_t __exittest(void)		\
	{ return exitfn; }					\
	void cleanup_module(void) __attribute__((alias(#exitfn)));


struct module中还包含了一些别的内容,包括模块名称,引用计数等。其中,引用计数一般是通过try_module_get增加的。
这个引用计数通常会影响模块的卸载。
sys_delete_module中会通过module_refcount获取要卸载的模块的引用计数。

要想让引用计数能正常工作,我们编写模块代码时,通常是在某个结构体的赋值代码中,加入如下一行。取决于模块的功能类型,这个结构体可能是file_operations、platform_driver、proto、proto_ops等。

.owner = THIS_MODULE

以下情形会影响模块的引用计数。
模块间的依赖关系。例如,模块A依赖B。A加载时,内核要解析A引用的外部符号。见module.c中的resolve_symbol。如果发现A引用的某个外部符号在B中,就调用use_module,记录A对B的依赖。use_module会增加B的引用计数,同时将A加入到B的使用者列表中去。
各种业务流程方面也会导致引用计数变化,好在内核框架代码已经为我们做好了这一切。
例如,当用户调用C库函数open打开一个文件时,__dentry_open中会调用fops_get获取要打开的文件的file_operations。而fops_get的定义如下,这就实现了对目标模块的引用计数的增加。
#define fops_get(fops) \
(((fops) && try_module_get((fops)->owner) ? (fops) : NULL))

再如,当用户创建一个socket时,__sock_create函数内会有如下代码。对实现此protocol family的模块,增加引用计数。

/*
 * We will call the ->create function, that possibly is in a loadable
 * module, so we have to bump that loadable module refcnt first.
 */
  if (!try_module_get(pf->owner))
      goto out_release;




看到没有,这些业务流程,都使用了owner成员。

所以,编写模块代码时,要是把“.owner  = THIS_MODULE”这句话漏了可就歇菜了 ^_^




再来观察__module_depends的定义,可见推测其内容是在加载时动态生成。


Linux modinfo命令教程:深入理解Linux内核模块(附案例详解和注意事项) modinfo(模块信息)命令在Linux系统中用于显示Linux内核模块的信息。此命令从命令行给出的Linux内核模块中提取信息。如果模块名称不是文件名,则默认搜索目录。modinfo可以理解来自任何Linux内核架构的模块 阅读详情

相关推荐

Linux内核模块开发

1.LINUX内核模块基础 1.1 什么是内核模块Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢?方法1:把所有的组件都编译进内核文件,即:zImage或bzImage,但这样会导致一个问题:占用内存过多。有没有一种机制能让内核文件本身并不包含某组件,而是在该组件需要被使用的时候,动态地添加到正在运行的内核中呢? 内核模块具有如下特点: 1)模块本身并不被编...

小虾米编程 1570

第一个linux驱动模块分析:

我们先看一下代码: #include <linux/module.h> #include <linux/init.h> // 模块安装函数 static int __init chrdev_init(void) { printk(KERN_INFO “chrdev_init helloworld init\n”); return 0; } // 模块卸载函数 stat...

qq_33472414的博客 560

Linux内核模块编程

Linux内核模块编程 (作者:Baron_wu 禁止转载) 首先,创建一个内核模块并插入Linux内核中。这是实验第一部分 首先查看当前内核模块使用情概况:lsmod Module模块名 Size:模块大小 Used by:这些模块在哪被使用 接下来编写一个simple.c的程序,当加载和卸载内核模块时给出适当的消息。 代码如下: #include &lt;linux/init.h&gt...

Baron_wu的博客 2137

再谈内核模块加载(一)—背景知识

注: 之前的分析可参考 <内核模块的加载> 在内核模块代码分析前,先简单介绍一下相关背景知识: 1.内核模块的编译分为两个阶段,可分别称为stage1和stage2: stage1主要负责将模块源码(*.c)编译为对应的目标(x.o)文件 stage2主要负责对每个模块生成一个.mod.c文件,其中记录了ko所需要的其他信息,将其编译为.mod.o,最终同模块的x.o共同链接(ld -r)为一个目标文件,这个目标文件即为最终的可加载模块(x.ko) 其中stage2是个批.....

ashimida 3492

Linux驱动基础详解】| Linux模块声明与描述

我们在编写一个模块的时候,常常使用一些宏定义来标识模块的作者,版本,以及相关信息的描述,如:`MODULE_AUTHOR`、`MODULE_DESCRIPTION`、`MODULE_LICENSE`、`MODULE_ALIAS`等,那么这些宏是如何进行管理的呢?

Donge's Blog 2241

linux 模块的使用

1.  如一段模块的代码:hellomod.c(点击) #include #include #include static int __init lkp_init (void){    printk (" Hello, world! from the kernel space...\n");    return 0;} static void __exit lkp_e

zhanglp的专栏 1295

Linux驱动】 Linux内核模块

Linux系统中,设备驱动会以内核模块的形式出现,学习Linux内核模块编程是驱动开发的先决条件。第一次接触Linux内核模块,我们将围绕着“Linux内核模块是什么”,“Linux内核模块的工作原理”以及 “我们该怎么使用Linux内核模块”这样的思路一起走进Linux内核世界。内核模块的概念:内核模块是什么东西?为什么引入内核模块这一机制?内核模块的原理:内核模块在内核中的加载、卸载过程,深入剖析内核模块如何导出符号。

C/C++软件工程师、嵌入式软件工程师、物联网研发工程师、C/C++讲师、物联网讲师、嵌入式讲师、鸿蒙讲师---欢迎大家一起交流(私信添加博主微信) 3091

Linux内核模块Linux内核模块简介

Linux操作系统中,内核模块(Loadable Kernel Module, LKM)是实现系统功能扩展的核心机制。2025年Linux 6.8版本引入的动态内核组件加载机制(DKLM)和AI增强模块,标志着内核模块技术进入全新发展阶段。本文将系统解析Linux内核模块的技术原理、开发实践,结合2025年最新特性,为开发者提供从入门到进阶的完整指南。

byte轻骑兵的技术小窝 1806

Linux内核模块Linux内核模块程序结构

如果你已经写过第一个 "Hello World" 内核模块,可能会好奇:为什么那个几行代码的程序能被内核识别?那些module_init、MODULE_LICENSE到底是什么意思?今天咱们就来扒一扒内核模块的程序结构,搞清楚一个合格的内核模块到底由哪些部分组成,每个部分又承担着什么角色。​

byte轻骑兵的技术小窝 2041

Linux内核模块详解

内核模块 实验目的 内核模块Linux操作系统中一个比较独特的机制。通过这一章学习,希望能够理解Linux提出内核模块这个机制的意义;理解并掌握Linux实现内核模块机制的基本技术路线;运用Linux提供的工具和命令,掌握操作内核模块的方法。 实验内容 针对三个层次的要求,本章安排了3个实验。 第一个实验,编写一个很简单的内核模块。虽然简单,但它已经具备了内核模块的基本要素。与此同时,...

Kunaly 2万+

Linux内核模块

模块是一种向LInux内核添加设备驱动程序,文件系统及其其他组件的有效方法,不需要编译新内核或者重启系统。

新法的博客 2497

linux 内核模块

另外,内存管理会提供虚拟内存的机制,该机制可以让进程使用多于系统可用Memory的内存,不用的内存会通过文件系统保存在外部非易失存储器中,需要使用的时候,再取回到内存中。Linux的文件系统模块采用先进的虚拟文件系统技术,屏蔽了各种文件系统的差别,为处理各种不同的文件系统提供了统一的接口,支持多种不同的物理文件系统达90多种。Linux 内核采用的是模块化技术,这样的设计使得系统内核可以保持最小化,同时确保了内核的可扩展性与可维护性,模块化设计允许我们在需要时才将模块加载至内核,实现动态内核的调整。

u010230019的博客 1676

Linux内核模块简介

当我们谈论Linux内核时,不可避免地要提到内核模块内核模块是一种动态加载到内核中的软件,它可以在运行时添加到内核中,从而扩展内核的功能。在这篇博客中,我们将深入探讨Linux内核模块的基本概念和作用,并通过一个简单的示例来展示如何创建和使用内核模块

qq_36733726的博客 2648

Linux驱动开发——内核模块

目录 内核模块的由来 第一个内核模块程序 内核模块工具 将多个源文件编译生成一个内核模块 内核模块参数 内核模块依赖 关于内核模块的进一步讨论 习题 内核模块的由来 最近一直在玩那些其它的技术,眼看快暑假了,我决定夯实一下我的驱动方面的技能,迎接我的实习,找了一本书,接下来就跟着这本书学了 先来看第二章,内核模块 Linux是宏内核(或单内核)的操作系统的典型代表,它和微内核(典型的代表是 Windows操作系统)的最大区别在于所有的内核功能都被整体

qq_52479948的博客 2684

Linux动态加载内核模块

Linux属于单内核,为了弥补单内核扩展性与维护性差的缺点,Linux引入动态可加载内核模块模块可以在系统运行期间加载到内核或从内核卸载。模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。下面是一个简单的例子: (1)模块hello.c文件#i

傻红就是不爱跑步的博客 2万+

Linux 驱动开发之内核模块开发 (一)—— 内核模块机制基础

一、内核模块的概念 1、什么是模块?        内核模块是一些可以让操作系统内核在需要时载入和执行的代码,同时在不需要的时候可以卸载。这是一个好的功能,扩展了操作系统的内核功能,却不需要重新启动系统,是一种动态加载的技术。 特点:动态加载,随时载入,随时卸载,扩展功能 2、内核模块的加载作用       内核模块只是向linux内核预先注册自己,以便于将来的请求使用;由目标代

知秋一叶 5763

小白学Linux内核模块编程

Linux内核模块编程Linux内核模块编程是一个很重要的知识点。尤其是编写底层驱动程序时,一定会涉及到它。内核模块编程也是Tiger哥学习Linux时第一节课所接触的知识。由此可以看出它的important,也可以看出其实它很easy。一前言:1.什么是内核模块1>内核模块是具有独立功能的程序。它可以被单独编译,但是不能单独运行,它的运行必须被链接到内核作为内核的一部分在内核空间中运行。 2> 模块编程和内核版本密切相连,因为不同的内核版本中某些函数的函数名会有变化。因此模块编程也可以说是内核编程。3>特

冀博 2万+

Linux内核模块

来修饰模块卸载函数,可以告诉内核如果相关的模块被直接被编译进内核(即build-in),则cleanup_function()函数就会被省略,直接不链进最后的镜像。#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) /* 所有人可读,用户可读|用户组可读|其他可读 */命令卸载掉某模块时,模块的卸载函数会被自动被内核执行,完成与模块加载函数相反的功能。(函数名)”的形式被指定,一般来说,模块卸载函数完成与模块加载函数相反的功能。

weixin_47596351的博客 1275
上一篇: Linux内核模块(驱动)编译详解
下一篇: 内核与用户态程序共享内存的方法
无忧老猪
博客等级 码龄17年 200粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值