【LinuxAPI分析】moduleinit与moduleexit Linux版本:4。191、前言 moduleinit与moduleexit用于我们驱动的加载,卸载,是我们驱动初始化退出的入口函数。moduleinit:内核启动时或者动态插入模块时调用moduleexit:驱动移除时调用 下面主要分析一下这两个接口的底层实现。 2、调用层次分析2。1moduleinitifndefMODULEmoduleinit()driverinitializationentrypointx:functiontoberunatkernelboottimeormoduleinsertionmoduleinit()willeitherbecalledduringdoinitcalls()(ifbuiltin)oratmoduleinsertiontime(ifamodule)。Therecanonlybeonepermodule。definemoduleinit(x)initcall(x);moduleexit()driverexitentrypointx:functiontoberunwhendriverisremovedmoduleexit()willwrapthedrivercleanupcodewithcleanupmodule()whenusedwithrmmodwhenthedriverisamodule。Ifthedriverisstaticallycompiledintothekernel,moduleexit()hasnoeffect。Therecanonlybeonepermodule。definemoduleexit(x)exitcall(x);elseMODULEInmostcasesloadablemodulesdonotneedcustominitcalllevels。Therearestillsomevalidcaseswhereadrivermaybeneededearlyifbuiltin,anddoesnotmatterwhenbuiltasaloadablemodule。Likebussnoopingdebugdrivers。defineearlyinitcall(fn)moduleinit(fn)definecoreinitcall(fn)moduleinit(fn)definecoreinitcallsync(fn)moduleinit(fn)definepostcoreinitcall(fn)moduleinit(fn)definepostcoreinitcallsync(fn)moduleinit(fn)definearchinitcall(fn)moduleinit(fn)definesubsysinitcall(fn)moduleinit(fn)definesubsysinitcallsync(fn)moduleinit(fn)definefsinitcall(fn)moduleinit(fn)definefsinitcallsync(fn)moduleinit(fn)definerootfsinitcall(fn)moduleinit(fn)definedeviceinitcall(fn)moduleinit(fn)definedeviceinitcallsync(fn)moduleinit(fn)definelateinitcall(fn)moduleinit(fn)definelateinitcallsync(fn)moduleinit(fn)defineconsoleinitcall(fn)moduleinit(fn)definesecurityinitcall(fn)moduleinit(fn)Eachmodulemustuseonemoduleinit()。definemoduleinit(initfn)staticinlineinitcalltmaybeunusedinittest(void){returninitfn;}intinitmodule(void)copy(initfn)attribute((alias(initfn)));Thisisonlyrequiredifyouwanttobeunloadable。definemoduleexit(exitfn)staticinlineexitcalltmaybeunusedexittest(void){returnexitfn;}voidcleanupmodule(void)copy(exitfn)attribute((alias(exitfn)));endif 2。2initcalldefineinitcall(fn)deviceinitcall(fn)defineexitcall(fn)staticexitcalltexitcallfnexitcallfn 2。3deviceinitcalldefinepureinitcall(fn)defineinitcall(fn,0)definecoreinitcall(fn)defineinitcall(fn,1)definecoreinitcallsync(fn)defineinitcall(fn,1s)definepostcoreinitcall(fn)defineinitcall(fn,2)definepostcoreinitcallsync(fn)defineinitcall(fn,2s)definearchinitcall(fn)defineinitcall(fn,3)definearchinitcallsync(fn)defineinitcall(fn,3s)definesubsysinitcall(fn)defineinitcall(fn,4)definesubsysinitcallsync(fn)defineinitcall(fn,4s)definefsinitcall(fn)defineinitcall(fn,5)definefsinitcallsync(fn)defineinitcall(fn,5s)definerootfsinitcall(fn)defineinitcall(fn,rootfs)definedeviceinitcall(fn)defineinitcall(fn,6)definedeviceinitcallsync(fn)defineinitcall(fn,6s)definelateinitcall(fn)defineinitcall(fn,7)definelateinitcallsync(fn)defineinitcall(fn,7s)defineinitcall(fn)deviceinitcall(fn) 2。4defineinitcallifdefCONFIGHAVEARCHPREL32RELOCATIONSdefinedefineinitcall(fn,id,sec)ADDRESSABLE(fn)asm(。sectionsec。init,ainitcallfnid:。longfn。。previous);elsedefinedefineinitcall(fn,id,sec)staticinitcalltinitcallfnidusedattribute((section(sec。init)))fn;endif 2。5、moduleinit调用顺序汇总moduleinitinitcalldeviceinitcalldefineinitcall(includelinuxinit。h)defineinitcall(includelinuxinit。h) 综上,我们调用顺序:moduleinit(fn)initcall(fn)deviceinitcall(fn)defineinitcall(fn,6) 3、源码分析 通过上面了解,我们最后调用的是defineinitcall的函数,下面我们主要分析该函数的意义。 了解之前呢,我们先来学习一下与的作用! 3。1与的作用 符号 作用 举例 符号可以是连接的意思 例如initcallfnid为initcallfnid那么,fntestinit,id6时,initcallfnid为initcalltestinit6 符号可以是字符串化的意思 例如id为id,id6时,id为6 3。2defineinitcalldefinedefineinitcall(fn,id)staticinitcalltinitcallfnidusedattribute((section(。initcallid。init)))fn 这里我们以moduleinit(testinit)为例,转换后的结果为:staticinitcalltinitcalltestinit6usedattribute((section(。initcall6。init)))testinit 通过attribute(section)设置函数属性,将testinit放在字段。initcall6。init中。 该字段通过链接器链接起来,形成一个列表进行统一管理。。。。。。。initcall6start。;KEEP((。initcall6。init))KEEP((。initcall6s。init))。。。。。。 还记得defineinitcall的定义吗?definepureinitcall(fn)defineinitcall(fn,0)definecoreinitcall(fn)defineinitcall(fn,1)definecoreinitcallsync(fn)defineinitcall(fn,1s)definepostcoreinitcall(fn)defineinitcall(fn,2)definepostcoreinitcallsync(fn)defineinitcall(fn,2s)definearchinitcall(fn)defineinitcall(fn,3)definearchinitcallsync(fn)defineinitcall(fn,3s)definesubsysinitcall(fn)defineinitcall(fn,4)definesubsysinitcallsync(fn)defineinitcall(fn,4s)definefsinitcall(fn)defineinitcall(fn,5)definefsinitcallsync(fn)defineinitcall(fn,5s)definerootfsinitcall(fn)defineinitcall(fn,rootfs)definedeviceinitcall(fn)defineinitcall(fn,6)definedeviceinitcallsync(fn)defineinitcall(fn,6s)definelateinitcall(fn)defineinitcall(fn,7)definelateinitcallsync(fn)defineinitcall(fn,7s)defineinitcall(fn)deviceinitcall(fn) 不同的宏定义,被赋予了不同的调用等级,最后将不同的驱动初始化函数统一汇总到initcallxstart字段统一管理,形成一个有序的列表。 这样,我们在内核中,按照顺序遍历这个列表,最后执行对应的模块初始化函数fn即可实现驱动的初始化。 这篇内容主要分析moduleinit的调用以及作用,后续再详细分析内核是如何调用初始化函数的。