Linux模块化机制和module_init

本文详细介绍了Linux模块化机制中的module_init,解释了如何动态加载和静态编译链接模块。通过示例代码展示了如何定义初始化和卸载函数,并通过module_init宏将它们与内核交互。在动态加载时,insmod命令调用sys_init_module系统调用来执行模块的初始化函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        致谢:

微信公众号:嵌入式企鹅圈 每天都新增爱好者关注,感谢大家的支持和大牛们的建议。本人将竭力出品更多优质的原创文章回馈大家的厚爱!


引子:模块化机制优点


模块化机制(module)是Linux系统的一大创新,是Linux驱动开发和运行的基础(当然,module并不仅仅是支撑驱动)。其优点在于:


1.在系统运行动态加载模块,扩充内核的功能。不需要时可以卸载。

2. 修改内核功能,不必重新全部编译整改内核,只需要编译相应模块即可。

3.模块目标代码一旦被加载重定位到内核,其作用域和静态链接的代码完全等价。

本文重点阐述Linux module加载的来龙去脉,其中的奥秘就在于对宏module_init的解读。


一、模块例子

hello_module.c代码如下:

#include <linux/module.h> /* Needed by all modules */

#include <linux/kernel.h> /* Needed for KERN_ALERT */

#include <linux/init.h> /*Needed for __init */


static int __init test_init(void){

printk(KERN_ALERT"Hello world!\n");

return 0;

}


static void __exit test_exit(void){

printk(KERN_ALERT"Goodbye world!\n");

}


module_init(test_init);

module_exit(test_exit);


二、模块编程要点

1.头文件 linux/module.h、linux/kernel.h、linux/init.h


2. 定义模块的初始化函数test_init(名字任意)和卸载函数test_exit(名字任意)。


3. 用宏module_init声明初始化函数,用宏module_exit声明卸载函数。


三、模块运行

模块代码有两种运行的方式:


1. 编译成可动态加载的module,并通过insmod来动态加载,接着进行初始化。


2. 静态编译链接进内核,在系统启动过程中进行初始化。


有些模块是必须要编译到内核,和内核一起运行的,从不卸载,如vfs、platform_bus等等。


### 后期初始化函数 `later_init` 模块初始化函数 `module_init` 在 Linux 内核开发中,`later_init` 并不是一个标准的术语或宏定义,但它可能指的是某些特定场景下的后期初始化逻辑。而 `module_init` 是一个广泛使用的宏,用于指定模块加载时执行的入口函数。 #### 1. **`module_init` 宏** `module_init` 是一种机制,允许开发者为内核模块指定一个初始化函数,在模块被加载到内核时自动调用该函数。其核心实现依赖于 GCC 的属性扩展功能 (`__attribute__((constructor))`) 或类似的链接器脚本技术[^4]。 以下是 `module_init` 的基本工作原理: - 当编译带有 `module_init(init_function)` 的代码时,`init_function` 被标记为需要优先运行的函数之一。 - 在模块加载过程中,内核会扫描这些特殊标记的函数并依次调用它们。 示例代码如下: ```c #include <linux/module.h> #include <linux/kernel.h> static int __init my_module_init(void) { printk(KERN_INFO "Module initialized\n"); return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "Module exited\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); ``` 上述代码中的 `my_module_init` 函数会在模块加载时被执行。 --- #### 2. **假设的 `later_init` 场景** 虽然没有官方文档提及名为 `later_init` 的具体概念,但在实际项目中可能存在类似的功能需求。例如,有些驱动程序或子系统希望延迟部分初始化操作直到更晚的时间点完成(比如等待其他组件准备好)。这种情况下可以手动设计类似于 `later_init` 的机制。 常见的做法包括但不限于以下几种方式: - 使用定时器接口(如 `timer_setup()`),安排某个延后的回调函数; - 利用工作队列(workqueue)提交异步任务; - 借助设备模型框架的通知链表监听事件触发条件满足后再继续处理剩余步骤; 下面是一个简单的例子展示如何通过 workqueue 实现所谓的 “late init” 功能: ```c #include <linux/workqueue.h> #include <linux/init.h> #include <linux/module.h> struct delayed_work my_late_init_work; void late_init_handler(struct work_struct *work) { pr_info("Late initialization completed.\n"); } DECLARE_DELAYED_WORK(my_late_init_work, late_init_handler); static int __init early_init(void){ queue_delayed_work(system_wq,&my_late_init_work,msecs_to_jiffies(500)); pr_info("Early initialization done, scheduling late init...\n"); return 0; } static void __exit cleanup_mod(void){ cancel_delayed_work_sync(&my_late_init_work); pr_info("Cleanup complete.\n"); } module_init(early_init); module_exit(cleanup_mod); MODULE_LICENSE("Dual BSD/GPL"); ``` 在这个案例里,“早起”的初始化由 `early_init` 执行完毕后立即调度了一个延迟作业去稍候再做额外的工作——即所谓“晚期”。 --- #### 3. **两者的对比** | 特性 | `module_init` | 自定义 `later_init` | |--------------------------|--------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| | 初始化时机 | 模块载入瞬间 | 可设定任意时间间隔 | | 是否内置支持 | 是 | 需要自行构建 | | 应用范围 | 主要用作模块启动阶段的核心配置 | 更适合那些需分多阶段逐步完善的复杂对象 | 需要注意的是,如果确实存在某种形式的标准 API 名叫 `later_init`,那么它应该属于某特定领域或者第三方补丁集的一部分而不是原生Linux Kernel所提供. --- ### 结论 综上所述,尽管两者都涉及到了系统的初始化过程,但是他们针对的应用场合以及具体的运作模式存在着明显的差异。对于常规意义上的插件化管理来说推荐采用成熟的 `module_init`;而对于更加精细控制的需求则考虑引入自定义方案诸如基于WorkQueue等手段达成目的。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值