如何从另一个模块调用导出的内核模块的功能呢?(How to call exported kernel

2019-06-18 01:10发布

我正在写一个API作为一个内核模块,提供设备驱动程序的各种功能。 我在写mycode.c中三种功能。 然后我建立和加载模块,然后将其复制成mycode.h <内核> /包括/ Linux操作系统 。 在设备驱动器,我有一个的#include <LINUX / mycode.h>和调用这些三个功能。 但是,当我建立了驱动模块,我得到三个链接器警告说,这些功能是不确定的

笔记:

  • 该函数声明中mycode.h EXTERN
  • 功能在mycode.c中使用EXPORT_SYMBOL(FUNC_NAME)导出
  • 运行命令纳米mycode.ko显示了所有三种功能如在符号表中是可用(大写T旁边,这意味着符号在文本(代码)节中找到)
  • 加载模块之后,将命令的grep FUNC_NAME的/ proc / kallsyms显示了所有三个功能作为加载

所以很明显的功能被正确导出和内核知道他们在哪里。 那么,为什么不能驾驶者看到自己的定义是什么? 任何想法,我缺少什么?


编辑:我发现这个了一些信息: http://www.kernel.org/doc/Documentation/kbuild/modules.txt

有时,外部模块使用从另一个外部模块导出的符号。 kbuild的需要有所有符号的充分了解,以免吐出未定义符号警告。 三个解决方案,针对这种情况存在。

注:建议采用顶级的kbuild文件的方法,但可能在某些情况下是不切实际的。

如果你有两个模块,foo.ko和bar.ko,其中foo.ko需要从bar.ko符号使用顶级的kbuild文件,可以使用通用顶级的kbuild文件,因此两个模块在同一个编译建立。 请看下面的目录布局:

  ./foo/ <= contains foo.ko ./bar/ <= contains bar.ko The top-level kbuild file would then look like: #./Kbuild (or ./Makefile): obj-y := foo/ bar/ And executing $ make -C $KDIR M=$PWD will then do the expected and compile both modules with full 

从任一模块的符号的知识。

使用一个额外的Module.symvers文件当外部模块内置,一个Module.symvers文件中生成含有未在内核中定义的所有导出的符号。 为了从bar.ko访问符号,从bar.ko汇编复制Module.symvers文件到foo.ko建立在目录。 在模块装配,kbuild的将读取Module.symvers外部模块的目录下的文件,并在构建完成后,会创建一个新的文件Module.symvers含定义的所有符号的内核的总和,而不是一部分。

使用“制造”变KBUILD_EXTRA_SYMBOLS如果是不切实际的,从另一个模块复制Module.symvers,你可以在你的build文件指定的文件到KBUILD_EXTRA_SYMBOLS空格分隔列表。 这些文件将被modpost其符号表的初始化过程中加载。

但所有这三个解决方案,以便对任何驱动程序才能使用我的API,那就要创建一个新的Makefile或直接访问我的文件Module.symvers? 这似乎有点不方便。 我希望他们只希望能够#包括我的头文件,并好到哪里去。 难道没有其他方法存在?

Answer 1:

从我的研究,似乎只有这些三种方式来处理这种情况,我已经得到了他们每个人的工作,所以我想我就挑我喜欢的淘汰者。



Answer 2:

最小QEMU + Buildroot里面示例

我已经测试在一个完全可重复的QEMU + Buildroot里面的环境下,或许有这方面的工作版本的版本将帮助你找出什么是屏幕ä与您的代码。

GitHub的上游的中心位于文件: dep.c | dep2.c | Makefile文件

dep.c:

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

int lkmc_dep = 0;
EXPORT_SYMBOL(lkmc_dep);
static struct task_struct *kthread;

static int work_func(void *data)
{
    while (!kthread_should_stop()) {
        printk(KERN_INFO "%d\n", lkmc_dep);
        usleep_range(1000000, 1000001);
    }
    return 0;
}

static int myinit(void)
{
    kthread = kthread_create(work_func, NULL, "mykthread");
    wake_up_process(kthread);
    return 0;
}

static void myexit(void)
{
    kthread_stop(kthread);
}

module_init(myinit)
module_exit(myexit)

dep2.c:

#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

extern int lkmc_dep;
static struct task_struct *kthread;

static int work_func(void *data)
{
    while (!kthread_should_stop()) {
        usleep_range(1000000, 1000001);
        lkmc_dep++;
    }
    return 0;
}

static int myinit(void)
{
    kthread = kthread_create(work_func, NULL, "mykthread");
    wake_up_process(kthread);
    return 0;
}

static void myexit(void)
{
    kthread_stop(kthread);
}

module_init(myinit)
module_exit(myexit)

现在,你可以这样做:

insmod dep.ko
insmod dep2.ko

但Buildroot里面也已经配置depmod /lib/module/*/depmod与依赖关系,所以只是这足以加载两个:

modprobe dep

如果您使用CONFIG_KALLSYMS_ALL=y ,则该符号可以看出有:

grep lkmc_dep /proc/kallsyms

还看到: 是否kallsyms有内核函数的所有符号?



Answer 3:

OK:您有一个模块:其中函数和一个地方有什么要进口是正确的?

您必须使用“EXPORT_SYMBOL(”函数名“),如在该功能所以在这个地方富。‘c’的文件具有的功能‘foo’的定义,并把在:EXPORT_SYMBOL(富)

请确保您有原型在一个共同的头文件“富”(你可以把它在每个模块具有单独的地方,它会工作,但你是在自找麻烦,如果签名更改)。 所以说:无效美孚(无效* ARG);

那么希望它只是调用“富”,你是好其他模块。

另外:请确保您以foo第一加载模块。 如果你有交叉依赖像模块2从模块1需要foo和模块1需要从模块2,你需要有另外一个寄存器的功能吧。 如果您想了解请咨询独立的Q.



文章来源: How to call exported kernel module functions from another module?