LinuxAPI分析moduleinit与moduleexit
【Linux API 分析】module_init与module_exit
Linux版本:4.19 1、前言
module_init 与 module_exit 用于我们驱动的加载,卸载,是我们驱动初始化/退出的入口函数。 module_init :内核启动时或者动态插入模块时调用 module_exit :驱动移除时调用
下面主要分析一下这两个接口的底层实现。
2、调用层次分析2.1 module_init #ifndef MODULE /** * 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_exit() - driver exit entry point * @x: function to be run when driver is removed * * module_exit() will wrap the driver clean-up code * with cleanup_module() when used with rmmod when * the driver is a module. If the driver is statically * compiled into the kernel, module_exit() has no effect. * There can only be one per module. */ #define module_exit(x) __exitcall(x); #else /* MODULE */ /* * In most cases loadable modules do not need custom * initcall levels. There are still some valid cases where * a driver may be needed early if built in, and does not * matter when built as a loadable module. Like bus * snooping debug drivers. */ #define early_initcall(fn) module_init(fn) #define core_initcall(fn) module_init(fn) #define core_initcall_sync(fn) module_init(fn) #define postcore_initcall(fn) module_init(fn) #define postcore_initcall_sync(fn) module_init(fn) #define arch_initcall(fn) module_init(fn) #define subsys_initcall(fn) module_init(fn) #define subsys_initcall_sync(fn) module_init(fn) #define fs_initcall(fn) module_init(fn) #define fs_initcall_sync(fn) module_init(fn) #define rootfs_initcall(fn) module_init(fn) #define device_initcall(fn) module_init(fn) #define device_initcall_sync(fn) module_init(fn) #define late_initcall(fn) module_init(fn) #define late_initcall_sync(fn) module_init(fn) #define console_initcall(fn) module_init(fn) #define security_initcall(fn) module_init(fn) /* Each module must use one module_init(). */ #define module_init(initfn) static inline initcall_t __maybe_unused __inittest(void) { return initfn; } int init_module(void) __copy(initfn) __attribute__((alias(#initfn))); /* This is only required if you want to be unloadable. */ #define module_exit(exitfn) static inline exitcall_t __maybe_unused __exittest(void) { return exitfn; } void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn))); #endif
2.2 __initcall #define __initcall(fn) device_initcall(fn) #define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
2.3 device_initcall #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)
2.4 ___define_initcall #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS #define ___define_initcall(fn, id, __sec) __ADDRESSABLE(fn) asm(".section "" #__sec ".init", "a" " "__initcall_" #fn #id ": " ".long " #fn " - . " ".previous "); #else #define ___define_initcall(fn, id, __sec) static initcall_t __initcall_##fn##id __used __attribute__((__section__(#__sec ".init"))) = fn; #endif
2.5、module_init调用顺序汇总 module_init ---> __initcall ---> device_initcall ---> __define_initcall(include/linux/init.h) ---> ___define_initcall(/include/linux/init.h)
综上,我们调用顺序: module_init(fn)---> initcall(fn) ---> device_initcall(fn) ---> define_initcall(fn, 6)
3、源码分析
通过上面了解,我们最后调用的是 ___define_initcall 的函数,下面我们主要分析该函数的意义。
了解之前呢,我们先来学习一下 # 与 ## 的作用!
3.1 # 与 ## 的作用
符号
作用
举例
##
"##"符号 可以是连接的意思
例如 initcall_##fn##id 为 initcall_fnid那么,fn = test_init,id = 6时, initcall_##fn##id为 initcall_test_init6
#
"#"符号 可以是字符串化的意思
例如 #id 为 "id",id=6 时,#id 为"6"
3.2 __define_initcall #define __define_initcall(fn, id) static initcall_t __initcall_##fn##id __used __attribute__((__section__(".initcall" #id ".init"))) = fn
这里我们以 module_init(test_init) 为例,转换后的结果为: static initcall_t __initcall_test_init6 __used __attribute__((__section__(".initcall6.init"))) = test_init
通过 __attribute__(__section__) 设置函数属性,将 test_init 放在字段 .initcall6.init 中。
该字段通过链接器链接起来,形成一个列表进行统一管理。 ...... __initcall6_start = .; KEEP(*(.initcall6.init)) KEEP(*(.initcall6s.init)) ......
还记得 __define_initcall 的定义吗? #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)
不同的宏定义,被赋予了不同的调用等级,最后将不同的驱动初始化函数统一汇总到 __initcallx_start 字段统一管理,形成一个有序的列表。
这样,我们在内核中,按照顺序遍历这个列表,最后执行对应的模块初始化函数 fn 即可实现驱动的初始化。
这篇内容主要分析 module_init 的调用以及作用,后续再详细分析内核是如何调用初始化函数的。
欲望太多会迷失本性有欲望没有错,错的是欲望之火迅猛地燃烧,一发不可收拾。每个人的心中都有一团欲望之火,我们既不能让这团火熄灭,也不能让它烧得太过猛烈。因为欲望之火熄灭,意味着人不思进取,没有斗志,没
缄默不言人长居于野,不复能言。若于世上,不可多言,看不惯亦不能言,久而久之,缄默不言。生来渺小,人微言轻,淡然处之,超脱世事。琴棋书画皆小道,谈古论今枉费心。浩宇宽广,透过现象找规律。查遗
水韵绍兴绍兴印象看完小时候语文课本中就存在的钱塘江大潮后,我们便驱车前往绍兴。开始了绍兴之旅鲁迅故里百草园中草半荒,三味书屋味更浓若将绍兴比喻成一部漂在水上的书,那么,鲁迅故里无疑就是全书
遇到农村自酿酒别着急买,极有可能是坑,建议大家弄懂再喝前两天老家的表妹结婚,我特意回了一次老家,已经许久没有回去了,家里已经有了很大的改变,之前的小土房都变成了一排排整齐的水泥房,之前到处都是土的地方,也被改造成了一个小广场,有很多老
燃油车主注意了,家用车车船税有调整,网友建议推广现阶段,汽车已成功进入千家万户。在传统燃油汽车备受青睐的时代,在新能源汽车的强势攻击下进一步满足了我们对低成本高车载配置的追求。特别是在燃油汽车遇到芯片短缺原材料价格上涨等问题后,
美媒组三队8人交易震动联盟,奥尼尔转发,勇士获得4号位完美答案今年NBA联盟有诸多豪门球队都过的很不如意,即便是去年的总冠军勇士队,如今也因为板凳席球员的状态问题,位居西部第12名。而湖人和篮网这些身处大城市的球队更是过得水深火热,篮网历经主
对比国外发言人我国三位女发言人真的错了吗?为什么会在短短时间内,就有三位中国女发言人被大家批判呢,首先是李少莉,因妆容服饰过于精致,用了两件奢侈品牌的配饰,就被当做了网爆的开端,引起一股风波。李少莉妆容精致接着换成朴素的张
李少莉事件都在等结果,听听小区阿姨怎么说最近网上热议的那个精致耳钉姐,火了这么久,大家都在静等她的调查结果!结果没出来前,还是那句话,清者自清,浊者自浊!说回大家热议的核心问题,想要知道什么样的结果呢?无非就是想知道她的
明明人老珠黄,非要尬演少女,这些女星我都替她羞有人说得体,在中年演员身上真的是难得的品质。比如说袁泉,在我的前半生中,她饰演的职场女高官唐晶,穿着一身利落的西装,走起路来都带风。不会花里胡哨,虽然有女二的玛丽苏恋爱戏码,但是永
你扎发好看还是披发好看?从这3点分析照做,想不美都难秋日生活打卡季有人说,美丽是一个储存罐,只要在每个细节上努力,就一定会看到成效。在生命鲜活青春美好的年岁,我们又怎能让美丽缺席呢?塑造更优秀美好的自己,那就从头开始吧!先解开被发型
运动鞋大衣秋冬最时髦洋气搭配,不挑年纪不挑身材大衣一直是秋冬季的首选,无论是时尚感还是保暖度,它都名列前茅。往期文章为大家分享了许多挑选大衣以及大衣与内搭之间的搭配技巧,但大家千万不要忘了,穿搭是要看整体的。想要穿搭整体完整和