Linux kernel 编译器/链接器如何解析像';printk';从linux上的模块调用

Linux kernel 编译器/链接器如何解析像';printk';从linux上的模块调用,linux-kernel,linux-device-driver,kernel,kernel-module,Linux Kernel,Linux Device Driver,Kernel,Kernel Module,我已经编写了一个示例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 cl

我已经编写了一个示例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");
}
#包括所有模块所需的/**/
#包含内核信息所需的/**/
int init_模块(void)
{
printk(KERN_INFO“Hello world.\n”);
返回0;
}
空洞清理_模块(空洞)
{
printk(KERN_INFO“再见世界1.\n”);
}

这里,我使用了“printk”方法,它是Linux公开的内核API。我可以在“/proc/kallsyms”中看到Linux导出的符号。我很想知道gcc/ld如何链接被调用的内核API?gcc/ld是否从“/proc/kallsyms”或其他文件获取内核方法的地址并执行链接?如果是,gcc/ld如何知道这一点?我无法找到任何选项来说明这一点。

Linux内核的模块加载器基本上包含一个专用的运行时链接器。ko文件实际上是一个对象文件,与其他任何文件一样,因此它附带了一个符号表。如果在上面运行
nm
nm
),您将看到许多标记为“U”的符号,即“未定义”。这包括模块使用的核心内核函数的符号,如
printk
\uu kmalloc
kfree
等,但在许多情况下也包括由其他模块实现的符号


当加载模块时,内核运行模块的未定义符号,并在(运行时)符号表中查找它们,修补相关内存位置,就像其他任何链接器一样。如果符号表中没有任何未定义的符号,加载将失败(使用
insmod
而不是
modprobe
很容易演示,因为它不会加载依赖项)。它还将模块导出的任何符号添加到符号表中,供其他模块使用,跟踪依赖项,以便您无法拉出另一个模块使用的模块。已链接到注释中模块加载器中的相关代码,如果您想了解所有血淋淋的详细信息,这将很有帮助。

感谢您的解释,我这么做太懒了:)