在Linux底下写过driver模块的对这个宏一定不会陌生。module_init宏在MODULE宏有没有定义的情况下展开的内容是不同的,如果这个宏没有定义,基本上表明阁下的模块是要编译进内核的(obj-y)。
1.在MODULE没有定义这种情况下,module_init定义如下:
#define module_init(x) __initcall(x);
因为
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) /
static initcall_t __initcall_##fn##id __used /
__attribute__((__section__(".initcall" level ".init"))) = fn
所以,module_init(x)最终展开为:
static initcall_t __initcall_##fn##id __used /
__attribute__((__section__(".initcall" level ".init"))) = fn
更直白点,假设阁下driver所对应的模块的初始化函数为int gpio_init(void),那么module_init(gpio_init)实际上等于:
static initcall_t__initcall_gpio_init_6
__used __attribute__((__section__(".initcall6.init"))) = gpio_init
;
就是声明一类型为initcall_t(typedef int (*initcall_t)(void))函数指针类型的变量__initcall_gpio_init_6并将gpio_init赋值与它。
这里的函数指针变量声明比较特殊的地方在于,将这个变量放在了一名为".initcall6.init"节中。接下来结合vmlinux
.lds中的
.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
__initcall_start = .;
*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init)
*(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init)
*(.initcall2.init) *(.initcall2s.init) *(.initcall3.init)
*(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init)
*(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init)
*(.initcall6.init) *(.initcall6s.init) *(.initcall7.init)
*(.initcall7s.init)
__initcall_end = .;
}
以及do_initcalls:
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++)
do_one_initcall(*call);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
那么就不难理解阁下模块中的module_init中的初始化函数何时被调用了:在系统启动过程中start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()。
2.在MODULE被定义的情况下(大部分可动态加载的driver模块都属于此, obj-m),module_init定义如下:
#define module_init(initfn) /
static inline initcall_t __inittest(void) /
{ return initfn; } /
int init_module(void) __attribute__((alias(#initfn)));
这段宏定义关键点是后面一句,通过alias将initfn变名为init_module。前面那个__inittest的定义其实是种技巧,用来对
initfn进行某种静态的类型检查,如果阁下将模块初始化函数定义成,比如,void gpio_init(void)或者是int
gpio_init(int),那么在编译时都会有类似下面的warning:
GPIO/fsl-gpio.c: In function '__inittest':
GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type
通过module_init将模块初始化函数统一别名为init_module,这样以后insmod时候,在系统内部会调用sys_init_module()去找到init_module函数的入口地址。
如果objdump -t gpio.ko,就会发现init_module和gpio_init位于相同的地址偏移处。简言之,这种情况下模块的初始化函数在insmod时候被调用。
分享到:
相关推荐
主要给大家介绍了关于PHP 7.1中AES加解密方法mcrypt_module_open()替换方案的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
lua解密工具微微有点老..也有不少不会编译的..本菜狗集成了一下.. 其实工具主要作用是处理unlua的中文问题.
plc s7-200 程式 模块 口令解密工具 结对好用
包含多个lua版本,内置详细配置JDK教程,轻松解密LUA加密文件
C#-AES加密+解密__-源码
本程序用于对凯撒密码的加解密,其中更是包含了,不需要密钥的暴力破解法,效率挺不错。
Zym PHP源码在线解密源码 将加密的文件 放到:encoded 目录中,解密后文件会放到:decoded 目录中
LUAC 脚本加密 , 用于LUAC 脚本反编译,有用得同学可以下载,
Hash在线解密平台最新版php实现纯txt存储哈希跟明文对应表查询
微信小程序解密工具_免安装版本.zip
des加解密算法, des加解密算法
此加解密算法DES使用56位密钥对64位的数据块进行加密,并对64位的数据块进行16轮编码。
PHP中加密解密函数与DES加密解密实例__1.docx
DES加密解密程序 可以实现对字符串的DES加密,并可以解密
通达信选股指标,748战疫版解密公式.tn6
有关数字图像处理【加解密】的一道源程序,是本人自己弄得 运行还可以
C#_加密解密类_DES_3DES_MD5
藏经阁-阿里新一代实时计算引擎Blink技术解密__61.pdf
luac解密工具 方便快捷的解密luac文件