modprobe -D vfat 最直接显示模块加载顺序,它读取 modules.dep.bin 按 insmod 实际顺序输出路径,但不校验文件存在、不检查符号可用性,仅做静态路径拼接。

modprobe -D 能直接看到模块加载顺序,但不校验文件存在
查某个模块(比如 vfat)加载时会拉哪些依赖,modprobe -D vfat 是最直接的命令。它读取 /lib/modules/$(uname -r)/modules.dep.bin,按 insmod 实际执行顺序逐行输出路径:
insmod /lib/modules/6.8.0-45-generic/kernel/fs/fat/fat.ko insmod /lib/modules/6.8.0-45-generic/kernel/fs/vfat/vfat.ko
注意三点:
-
$(uname -r)是真实展开的内核版本号,不是占位符;若对应目录在/lib/modules/下缺失,-D仍可能成功输出,但后续modprobe vfat必然失败 - 拼错模块名、或
.ko文件根本不存在,-D也不报错——它只做静态路径拼接,不检查文件是否存在 - 这个顺序是“理论加载链”,不代表一定能成功加载;比如
fat.ko缺失、签名未通过 Secure Boot,-D照样输出,modprobe却会卡在Operation not permitted
/proc/kallsyms 是唯一能确认符号是否真正可用的来源
当模块加载报 Unknown symbol in module,说明运行时符号没找到。这时候不能看 nm 或 Module.symvers,得查 /proc/kallsyms:
sudo cat /proc/kallsyms | grep 'shared_func\|module_a'
输出形如:
ffffffffc1234567 t shared_func [module_a]
关键看三处:
- 第二列
t是小写 → 局部符号,其他模块不可见;必须是大写T(函数)或D(已初始化变量)才可被依赖 - 方括号里的
[module_a]表示该符号由哪个模块导出;若没出现,说明模块没加载,或没用EXPORT_SYMBOL导出 - 非 root 用户看到的地址全是
0000000000000000,必须加sudo
nm + Module.symvers 才能查编译期依赖,不是运行时问题
想提前知道一个未加载的 .ko 文件依赖哪些符号,得用 nm:
nm module_b.ko | grep "U "
U 表示未定义符号,即它要调但自己没实现的东西。但光有这个不够,还得确认这些符号到底来自哪个模块——这靠 Module.symvers:
- 该文件由导出模块(如
module_a)编译生成,记录了每个导出符号所属模块和 CRC 校验值 - 依赖模块(如
module_b)编译前,必须把module_a/Module.symvers复制到自己的源码目录,否则编译会报WARNING: modpost: missing symbol -
Module.symvers不参与运行时,只影响编译;即使它缺失,模块也能加载,只要符号在/proc/kallsyms中存在且可见
depmod -a 是所有依赖工具的前提,漏掉就全失效
modprobe -D、lsmod 显示依赖、甚至 modprobe vfat 能否成功,都依赖 modules.dep.bin 文件。它由 depmod -a 生成:
sudo depmod -a
这个动作扫描 /lib/modules/$(uname -r)/ 下所有 .ko 文件,分析 MODULE_INFO(depends, "") 和符号关系,更新:
-
/lib/modules/$(uname -r)/modules.dep(文本格式) -
/lib/modules/$(uname -r)/modules.dep.bin(modprobe实际读取的二进制文件)
常见场景:modprobe -D vfat 输出为空、或提示 Module vfat not found,大概率就是 depmod -a 没跑过,或者刚装了新模块但没重建依赖。
真正容易被忽略的是:依赖关系分三层——编译期靠 Module.symvers,加载顺序靠 modules.dep.bin,运行时符号有效性只看 /proc/kallsyms。三者缺一不可,但各自解决的问题完全不同,混用就会查半天找不到原因。


















