解密module_init

原文 : http://blog.163.com/xinbuqianjin@126/blog/static/167563447201010221231507/


在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时候被调用。

### 解决 Python 中 `Crypto.Cipher` 模块导入 AES 出现的 ImportError 问题 当遇到 `ImportError: No module named Crypto.Cipher` 或者无法从 `Crypto.Cipher` 导入 AES 的错误时,这通常是因为安装了不正确的库或者环境配置存在问题。 #### 安装正确版本的加密库 对于 Anaconda3 用户来说,建议使用 `pycryptodome` 库而不是简单的 `crypto`。因为后者可能不会提供完整的功能集,并且名称大小写的敏感性可能导致导入失败。可以通过以下命令来安装: ```bash pip uninstall crypto pip install pycryptodome ``` 如果希望加速下载过程,在 Linux 下可以采用国内源进行安装: ```bash pip install -i https://pypi.douban.com/simple pycryptodome ``` #### 修改导入语句 安装完成后,应该确保使用的导入路径是正确的。有时即使已经正确安装了 `pycryptodome`,仍然会收到类似的错误提示。这时应当调整导入语句中的模块名,将其改为 `Cryptodome` 而不是 `Crypto`[^3]: ```python from Cryptodome.Cipher import AES ``` #### 验证安装效果 为了确认安装是否成功以及能否正常工作,可以在交互式的 Python shell 中尝试执行如下测试代码片段: ```python >>> from Cryptodome.Signature import PKCS1_v1_5 ``` 如果没有抛出异常,则表示安装有效,上述提到的导入错误已经被解决[^2]。 #### 使用示例 一旦解决了依赖项的问题并能够顺利导入所需的类之后,就可以按照下面的方式来进行基本的数据加解密操作了: ```python import base64 from Cryptodome.Cipher import AES def pad(text): while len(text) % 16 != 0: text += b' ' return text data = b'Hello, world!' key = b'Sixteen byte key' cipher = AES.new(key, AES.MODE_ECB) # Encrypting the data padded_data = pad(data) encrypted_message = cipher.encrypt(padded_data) print('Encrypted message:', base64.b64encode(encrypted_message).decode()) # Decrypting the data decrypted_padded_message = cipher.decrypt(encrypted_message) original_message = decrypted_padded_message.rstrip() print('Decrypted original message:', original_message.decode()) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值