Linux kernel 是否可以延迟加载导出符号?

Linux kernel 是否可以延迟加载导出符号?,linux-kernel,kernel-module,kernel,Linux Kernel,Kernel Module,Kernel,我正在处理一些linux内核模块,有一个与循环加载问题相关的问题 模块A首先加载并导出许多符号供模块B或C使用。模块B或C随后加载,符号存在以供使用 但是,我现在发现模块A需要来自模块B或C的符号,但仅在运行时使用,不需要初始化模块。当然,当A加载时,它会发现符号还不存在。我甚至在模块A中将符号标记为extern,但这也不起作用 在模块a加载后是否可以延迟加载符号,尽管它在B或C加载之前还不存在?如果您知道符号的类型/原型,请尝试在运行时使用kallsyms\u lookup\u name()获

我正在处理一些linux内核模块,有一个与循环加载问题相关的问题

模块A首先加载并导出许多符号供模块B或C使用。模块B或C随后加载,符号存在以供使用

但是,我现在发现模块A需要来自模块B或C的符号,但仅在运行时使用,不需要初始化模块。当然,当A加载时,它会发现符号还不存在。我甚至在模块A中将符号标记为extern,但这也不起作用


在模块a加载后是否可以延迟加载符号,尽管它在B或C加载之前还不存在?

如果您知道符号的类型/原型,请尝试在运行时使用
kallsyms\u lookup\u name()
获取指向所需符号的指针,而不是作为外部符号链接到它(意思是让加载程序在加载时为您查找)。可以使用您喜爱的搜索引擎找到示例。

这种情况通常通过回调解决

假设模块A导出函数以注册/注销回调。B和/或C使用这些函数并向A提供适当的回调。需要时,A检查回调是否已设置并调用它们

类似这样的内容(为了简单起见,没有错误处理和锁定):

这类似于内核中的文件操作和许多其他回调操作。假设用户希望读取(例如)由自定义驱动程序维护的字符设备。内核本身(确切地说是VFS)接收请求但无法自行处理。它将请求转发给已为该设备注册其文件操作回调的自定义驱动程序。反过来,驱动程序使用内核本身导出的函数,如
cdev_add()
,等等

/* Module A */
struct a_ops /* Better to define struct a_ops in a header file */
{
    void (*needed_func)(void);
    void (*another_needed_func)(void);
}; 
...
struct a_ops ops = {
    .needed_func = NULL;
    .another_needed_func = NULL;
};
...
int a_register_needed_funcs(struct a_ops *a_ops)
{
    ops.needed_func = a_ops->needed_func;
    ops.another_needed_func = a_ops->another_needed_func;
}
EXPORT_SYMBOL(a_register_needed_funcs);

void a_unregister_needed_funcs()
{
    ops.needed_func = NULL;
    ops.another_needed_func = NULL;
}
EXPORT_SYMBOL(a_unregister_needed_funcs);

...
/* Call the specified callbacks when needed: */
void do_something(void)
{
    if (ops.needed_func != NULL) {
        ops.needed_func();
    }
    else {
            /* the callback is not set, handle this: report error, ignore it or
             * do something else */
            ...
    }
}
...

/* Modules B and C */
/* Their code #includes the file where struct a_ops is defined. 
 * The module registers the callbacks, for example, in its init function
 * and unregister in exit function. */
...
static void func(void)
{
    ...
}

static void another_func(void)
{
    ...
}

struct a_ops my_funcs = {
    .needed_func = func;
    .another_needed_func = another_func;
};

int __init my_module_init(void)
{
    ...
    result = a_register_needed_funcs(&my_funcs);
    ... 
}
void __exit my_module_exit(void)
{
    ...
    a_unregister_needed_funcs();
    ...
}