module_init功能分析

module_init在Linux内核驱动程序中起到关键作用,决定驱动是静态链接还是动态加载。静态链接时,module_init将驱动编译进内核,而动态加载则生成*.ko文件,可在需要时插入内核。在内核启动过程中,do_initcalls函数会按顺序调用.initcall段中的初始化函数,完成驱动初始化。

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

每次在编写驱动的程序的时候,都会在程序的最后加上module_init()的字样,那么module_init到底起什么作用呢?

static int hello_init(void)
{
    printk("Hello Hanrui\n");
    return 0;
}
 
static void hello_exit(void)
{
    printk("Hanrui\n");
}
 
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

在Linux内核中,我们知道,一段程序有两种方式可以被内核执行:

一、在子目录的Makefile中,将文件定义为obj-y += xxx ,这种方式将该程序静态链接进内核中,在内核启动的时候直接运行。

二、在子目录的Makefile中,将文件定义为obj-m += xxx,而这种方式最后会生成*.ko文件,可以由用户在想加入内核时动态链接进内核中。一旦可动态加载的模块目标代码(.ko)被加载重定位到内核,其作用域和静态链接的代码是完全等价的。所以这种运行方式的优点显而易见:

  1. 可根据系统需要运行动态加载模块,以扩充内核功能,不需要时将其卸载,以释放内存空间;
  2. 当需要修改内核功能时,只需编译相应模块,而不必重新编译整个内核。

采用哪种方式加载进内核的,就是由module_init()决定的。

在内核代码中我们会看到。

#ifndef MODULE
...
#define module_init(x)  __initcall(x);
...
#else
 
#define module_init(initfn) \
    int init_module(void) __attribute__((alias(#initfn)));
...
#endif

从上面的代码可以看出来,决定采用哪种编译方式由 MODULE决定。上面部分用于将模块静态编译连接进内核,下面部分用于编译可动态加载的模块。

1、静态链接即编译为*.o文件链接进内核中

很显然,采用这种方式,走的上面的分支。其调用过程如下:

#define module_init(x)  __initcall(x);
--> #define __initcall(fn) device_initcall(fn)
    --> #define device_initcall(fn)     __define_initcall(fn, 6)
        --> #define __define_initcall(fn, id) \
                static initcall_t __initcall_##fn##id __used \
                __attribute__((__section__(".initcall" #id ".in
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值