【Linux】【调试】module_init的执行顺序引起的问题及相应处理

  • 🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)
  • 🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd
  • 🌐系列专栏:Linux技术
  • 📰如觉得博主文章写的不错或对你有所帮助的话,还望大家三连支持一下呀!!! 👉关注✨、点赞👍、收藏📂、评论。
  • 如需转载请参考转载须知!!

引言

  • 最近在调试一个功能,其中一个配置项需要在内核中增加proc文件。类似于这种:
wifi_param_config/special_pkt_process/enable
wifi_param_config/special_pkt_process/interface

其中,wifi_param_config是已有的proc文件目录,本次需要新增special_pkt_process这个目录和enable、interface两个文件。
wifi_param_config和special_pkt_process通过单独的两个函数来建立,并通过module_init来执行的。

  • 相关代码如下:
#file name:wifi_param_config.c
static int __init wifi_param_config_init(void)
module_init(wifi_param_config_init);
#file name:special_pkt_process.c
static int __init special_pkt_process_init(void)
module_init(special_pkt_process_init);
file name:Makefile
obj-y += special_pkt_process.o
obj-y += wifi_param_config.o
  • 测试发现,建special_pkt_process目录会失败。

分析过程

  • 经过分析,怀疑可能和父目录的建立时序有关。通过在init函数中加打印证实了这一点。

关于module_init

  • 相关代码如下:
#define pure_initcall(fn)		__define_initcall(fn, 0)

#define core_initcall(fn)		__define_initcall(fn, 1)
#define core_initcall_sync(fn)		__define_initcall(fn, 1s)
#define postcore_initcall(fn)		__define_initcall(fn, 2)
#define postcore_initcall_sync(fn)	__define_initcall(fn, 2s)
#define arch_initcall(fn)		__define_initcall(fn, 3)
#define arch_initcall_sync(fn)		__define_initcall(fn, 3s)
#define subsys_initcall(fn)		__define_initcall(fn, 4)
#define subsys_initcall_sync(fn)	__define_initcall(fn, 4s)
#define fs_initcall(fn)			__define_initcall(fn, 5)
#define fs_initcall_sync(fn)		__define_initcall(fn, 5s)
#define rootfs_initcall(fn)		__define_initcall(fn, rootfs)
#define device_initcall(fn)		__define_initcall(fn, 6)
#define device_initcall_sync(fn)	__define_initcall(fn, 6s)
#define late_initcall(fn)		__define_initcall(fn, 7)
#define late_initcall_sync(fn)		__define_initcall(fn, 7s)

#define __initcall(fn) device_initcall(fn)

/**
 * module_init() - driver initialization entry point
 * @x: function to be run at kernel boot time or module insertion
 *
 * module_init() will either be called during do_initcalls() (if
 * builtin) or at module insertion time (if a module).  There can only
 * be one per module.
 */
#define module_init(x)	__initcall(x);
  • module_init 其实是一个宏,而并非函数,最终都是通过__define_initcall这个调用来实现的。__define_initcall通过其中的参数,可以控制不同__define_initcall的调用顺序。

module_init函数的执行顺序

  • 同是module_init的函数,调用顺序没有高与低,但是总有执行的先后。
  • 原理分析:
    – Linux源码在编译的时候,通过使用module_init告知编译器链接,自定义一个专门用来存放这些初始化函数的地址段,将对应的函数入口统一放在一起;
    – 内核启动的时候统一扫描这个段的开始,按照顺序,可以执行所有这些初始化函数;
                    |-------------------|
                    |   .... .... ..... |

                    |  .initcall6.init  | ---- device_initcall
                    
                    |   .... .... ..... |
                    |-------------------|
  • 核心源码如下:
static void __init do_initcalls(void)
{
	initcall_t *call;
	for (call = __initcall_start; call < __initcall_end; call++) {
		 ...
		(*call)();
    }
}

从中不难看出,__define_initcall中不同等级的的初始化函数,module_init中的同一等级的函数。在底层调用时是一视同仁的,只是按顺序逐个调用,严格来说,是按地址顺序(从低到高)调用的。

两个函数的地址

  • 通过System.map(或/proc/kallsyms)可以查看两个init函数的顺序:
linux/System.map 
c0888e1c t special_pkt_process_init
c0888e34 t wifi_param_config_init
  • 按前面分析,果然吻合,父目录的初始化函数在后,地址较高。

两个函数地址的高低如何确定

  • 函数地址的高低实际上是由链接过程(链接顺序)决定的;
  • 链接先后顺序,默认以makefile里面文件的先后顺序做依据,否则先后顺序由链接脚本指定。在这里,是由makefile决定的。

解决方案

修改Makefile,先链接父目录对应文件:

obj-y += wifi_param_config.o
obj-y += special_pkt_process.o

修改C文件

  • 将special_pkt_process_init移到wifi_param_config_init函数中,不再使用module_init调用。

如本文对你有些许帮助,欢迎大佬加关注、评论、点赞,有关必回关

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花神庙码农

你的鼓励是我码字的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值