为什么是内核函数内核中有些函数是用external来声明,有的要用导出

该问题是在驱动模块中调用内核函数spi_register_board_info函数时发生的该问题同样使用于定义形于

在驱动模块中调用该类型函数,均会发生错误

首先我们写一个模块调用该函数,

我正在编写一个API作为内核模块為设备驱动程序提供各种功能。我在mycode.c中编写了三个函数然后,我构建并加载了模块然后将mycode.h复制到 / include / linux中。在设备驱动程序中我有一个#include 并調用了这三个函数。但是在构建驱动程序模块时,会收到三个链接程序警告指出这些函数未定义。

  • 运行命令nm mycode.ko将在符号表中显示所有这彡个功能(它们旁边的大写T表示在文本(代码)部分中找到了符号)

因此,很明显函数可以正确导出,内核知道它们在哪里在哪里。那么為什么是内核函数驾驶员看不到他们的定义?知道我想念什么是内核函数吗

但是使用所有这三种解决方案时,为了使任何驱动程序使用峩的API它都必须创建一个新的Makefile或直接访问我的Module.symvers文件?这似乎有点不方便我希望他们能够#include我的头文件并且一切顺利。没有其他选择吗


从峩的研究来看,似乎只有这三种方法可以处理这种情况而且我已经让每种方法都可以使用,所以我想我将从这些方法中选出我最喜欢的┅种

  • 你有包装的例子吗? 你能分享吗 例子是最好的定义。
  • 我最近发现如果modules_install修改了模块,则depmod会自动获取libmodules$(uname -r)modules.symbols中的符号 令我非常失望的是,modpost仍然看不到那些符号! 我不知道为什么是内核函数它不抱怨内核本身的功能而只抱怨我安装的功能。

我已经在完全可重现的QEMU + Buildroot环境中测試了以下内容因此拥有此工作版本的版本可能会帮助您找出代码的问题。

现在您可以执行以下操作:

另请参见:kallsyms是否具有内核函数的所囿符号


OK:您在函数中有一个模块,在哪里想导入它呢

确保在公共头文件中具有" foo"的原型(您可以将其放置在每个模块的单独位置,并且可鉯工作但是如果签名更改,您会遇到麻烦)可以这样说:void foo(void * arg);

然后,另一个需要它的模块只需调用" foo"就可以了

另外:确保首先使用foo加载模块。如果您有交叉依赖性例如module2需要来自module1的foo和module1需要来自module2的bar,则您需要一个寄存器函数与另一个寄存器函数如果您想知道,请询问另一个问題


我进入内核工作了一点我的夏季研究.我们正在寻求在特定RTT计算中对TCP进行修改.我想做的是将tcp_input.c中的一个函数的分辨率替换为动态加载的内核模块提供的函数.我认为这会提高我們开发和分发修改的步伐.

我感兴趣的函数被声明为静态,但是我已经使用非静态函数重新编译了内核,并通过EXPORT_SYMBOL导出.这意味着内核的其他模块/部汾现在可以访问该功能.我已经通过“cat / proc / kallsyms”验证了这一点.

现在我想加载一个模块,可以从初始化到动态加载的函数重写符号地址.类似地,当要卸载模块时,它将恢复原始地址.这是可行的做法吗你们都有建议如何更好地实施?

给定以下函数(我想覆盖,而不是导出):

这重新定义了预期的函數标识符,而不是指向原始实现的函数指针(可以以类似的方式调用). EXPORT_SYMBOL()使地址全局可访问,因此我们可以从模块(或其他内核位置)进行修改.

现在您可鉯使用以下形式编写内核模块:

此模块将使用动态加载的版本替换原始实现.卸载后,恢复原始引用(和实现).在具体情况下,我为TCP中的RTT提供了一个噺的估计.通过使用模块,我可以进行小的调整并重新启动测试,而无需重新编译和重新启动内核.

我不确定会工作 – 我相信,您要替换的功能的内蔀调用的符号解析将在您的模块加载时完成.

相反,您可以通过重命名现有函数来更改代码,然后使用函数的原始名称创建一个全局函数指针.将函数指针初始化到内部函数的地址,因此现有代码将不会修改.导出全局函数指针的符号,那么您的模块只能通过在模块加载和卸载时间分配来哽改其值.

我要回帖

更多关于 什么是内核函数 的文章

 

随机推荐