【问题标题】:Can the loading of exported symbols be delayed?可以延迟加载导出的符号吗?
【发布时间】:2013-06-06 13:00:30
【问题描述】:

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

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

但是,我现在发现模块 A 需要来自模块 B 或 C 的符号,但仅在运行时,不需要初始化模块。因此,当 A 加载时,它当然会发现该符号尚不存在。我什至在模块 A 中将符号标记为 extern,但这也没有用。

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

【问题讨论】:

    标签: linux-kernel kernel-module kernel


    【解决方案1】:

    此类情况通常使用回调来解决。

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

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

    /* 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();
        ...
    }
    

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2018-04-02
        • 2011-08-25
        • 2012-04-05
        • 1970-01-01
        • 1970-01-01
        • 2012-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多