我编写了一个示例 hello.ko 内核模块:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
int init_module(void)
{
printk(KERN_INFO "Hello world.\n");
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
在这里,我使用了“printk”方法,它是 Linux 公开的内核 API。我可以在“/proc/kallsyms”中看到Linux导出的符号。我很好奇 gcc/ld 如何链接调用的内核 API? gcc/ld 是否从“/proc/kallsyms”或其他文件获取内核方法的地址并执行链接?如果是,gcc/ld 如何知道这一点?我无法找到任何可以说明这一点的选项。
Linux 内核的模块加载器基本上包含一个专用的运行时链接器。 .ko 文件实际上是一个像其他文件一样的目标文件,因此它带有一个符号表。如果你跑nm
on it (nm <path/to/some_module.ko>
),你会看到很多标记为“U”的符号,即“未定义”。这包括模块使用的核心内核函数的符号,例如printk
, __kmalloc
, kfree
等等,但在许多情况下还有其他模块实现的符号。
加载模块时,内核会运行模块的未定义符号,并在(运行时)符号表中查找它们,修补相关的内存位置,就像任何其他链接器一样。如果符号表中尚不存在任何未定义的符号,则加载将失败(可以使用以下命令轻松演示)insmod
代替modprobe
因为它不会加载依赖项)。它还将模块导出的任何符号添加到符号表中以供其他模块使用,跟踪依赖关系,这样您就无法删除另一个模块使用的模块。伊利亚·马特维奇科夫在注释中链接到模块加载器中的相关代码,如果您想了解所有详细细节,这将有所帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)