Linux驱动的加载与卸载
1.驱动加载与卸载命令
1.1 insmod命令
insmod [选项] <模块文件>
选项:指定
insmod命令的其他行为或输出。模块文件:要加载的内核模块文件,通常是以
.ko结尾的文件。
以下是一般的选项,具体支持的选项以实际为准。
| 选项 | 作用 |
|---|---|
-f | 强制加载内核模块,即使它存在依赖问题或已加载相同模块。 |
-v | 显示详细的输出,提供更多的调试信息。 |
-h | 显示帮助信息。 |
--dry-run | 模拟加载操作,但不实际加载模块,用于测试和诊断。 |
--verbose | 显示更详细的加载信息。 |
例如:

1.2 rmmod命令
1.3 modprobe与insmod
modprobe能够自动加载模块,并智能处理依赖关系。无需指定路径:只需提供模块名(如 usb-storage),系统会自动从默认路径(/lib/modules/$(uname -r)/)中查找模块文件(依赖 modules.dep 等索引文件)。
自动处理依赖:加载模块时,会先检查并自动加载其所有依赖的模块(例如加载 A 时,若依赖 B,则先加载 B 再加载 A)。

2.驱动加载失败定位思路
- dmesg查看有没有报错信息
- 如果是PCI设备查看pci是否有扫描到,例如:lspci | grep 1eb6
- 检查固件侧是否正常运行
- 查看当前驱动加载情况,例如:lsmod | grep scgbe
3.驱动加载与卸载流程
3.1关于insmod
- insmod是一个用户态程序(位于 /sbin/insmod),接收用户传入的模块文件完整路径作为参数(必须是绝对路径或相对路径,无法仅通过模块名查找)。
- insmod 打开指定的模块文件,读取其二进制数据(包括模块代码、数据、符号表、依赖信息等)到用户态内存中。通过finit_module 系统调用将文件描述符传递给内核(更高效,避免用户态到内核态的大数据拷贝)。
- insmod 的源码非常精简,核心功能是通过系统调用将模块文件传递给内核,本身不处理依赖或复杂逻辑。其设计体现了 Linux “用户态工具做简单封装,复杂逻辑在内核实现” 的思想。若需深入研究,可结合kmod源码和Linux内核的模块管理代码(kernel/module.c)
- 内核通过 sys_init_module 或 sys_finit_module 函数处理用户态的系统调用(位于内核源码 kernel/module.c
3.1驱动程序的入口函数如何开始执行
- 驱动模块(.ko 文件)是ELF二进制格式,其中包含多个段(如代码段、数据段、符号表、特殊元数据段)。module_init 标记的入口函数会被编译到 .init.text 段(初始化代码段),同时其地址会被记录到模块的 “模块信息结构” 中,该结构是内核解析入口函数的关键。
- 当内核通过sys_init_module或sys_finit_module系统调用加载模块时,会执行以下步骤找到入口函数:
(1)解析 ELF 格式,定位模块元数据
内核首先解析.ko 文件的 ELF头,找到包含模块元数据的特殊段(通常是 __ksymtab、__param、__modinfo 等段,不同内核版本可能有差异)。这些段中包含一个关键结构:struct module(模块描述符),它是内核管理模块的核心数据结构,其中记录了入口函数、出口函数、依赖符号等所有关键信息。
(2)从 struct module 中提取入口函数地址
struct module 中有一个成员 init,专门用于存储入口函数的地址。例如(简化版结构体):
struct module {// ... 其他成员 ...int (*init)(void); // 入口函数指针void (*exit)(void); // 出口函数指针// ... 其他成员 ...
};找到入口函数地址后就可以调用入口函数:模块初始化的最终执行
模块卸载逻辑类似。
