insmod后发生了什么

通过 insmod 命令加载 ko 内存模块,加载该内存模块的时候,该内存模块会自动执行module_init() 函数,进行初始化操作。

#ifndef MODULE
// 省略
#define module_init(x)	__initcall(x);
// 省略
#else

#define module_init(initfn)	\
	int init_module(void) __attribute__((alias(#initfn)));
// 省略
#endif

insmod 会通过文件系统将 .ko 模块读到用户空间的一块内存中,然后执行系统调用sys_init_module() 解析模组,代码如下:

1 SYSCALL_DEFINE3(init_module, void __user *, umod,
2 unsigned long, len, const char __user *, uargs)
3 {
4 int err;
5 struct load_info info = { };
6
7 err = may_init_module();
8 if (err)
9 return err;
10
11 pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
12 umod, len, uargs);
13
14 err = copy_module_from_user(umod, len, &info);
15 if (err)
16 return err;
17
18 return load_module(&info, uargs, 0);
19 }

• 第 14 行:通过 vmalloc 在 vmalloc 区分配内存空间,将内核模块 copy 到此空间,info->hdr直接指向此空间首地址,也就是 ko 的 elf header 。

• 第 18 行:然后通过 load_module() 进行模块加载的核心处理,在这里完成了模块的搬移,重定向等艰苦的过程。

 下面是 load_module() 的详细过程,代码已经简化,主要包含 setup_load_info()layout_and_allocate()

1 /* 分配并加载模块 */
2 static int load_module(struct load_info *info, const char __user *uargs,
3 					   int flags)
4 {
5 		struct module *mod;
6 		long err = 0;
7 		char *after_dashes;
8 		...
9 		err = setup_load_info(info, flags);
10		 ...
11 		mod = layout_and_allocate(info, flags);
12 		...
13 }

• 第 9 行:setup_load_info() 加载 struct load_infostruct module, rewrite_section_headers,将每个 section 的 sh_addr 修改为当前镜像所在的内存地址,section 名称字符串表地址的获取方式是从 ELF 头中的 e_shstrndx 获取到节区头部字符串表的标号,找到对应 section 在 ELF 文件中的偏移,再加上 ELF 文件起始地址就得到了字符串表在内存中的地址。

• 第 11 行:在 layout_and_allocate() 中,layout_sections() 负责将 section 归类为 core 和 init 这两大类, 为 ko 的第二次搬移做准备。move_module() 把 ko 搬移到最终的运行地址。内核模块加载代码搬运过程到此就结束了。

总结:首先 insmod 会通过文件系统将 .ko 模块读到用户空间的一块内存中,然后执行系统调用sys_init_module() 解析模组, 这时,内核在 vmalloc 区分配与 ko 文件大小相同的内存来暂存ko 文件,暂存好之后解析 ko 文件,将文件中的各个 section 分配到 init 段和 core 段,在 modules 区为 init 段和 core 段分配内存,并把对应的 section 复制到 modules 区最终的运行地址,经过 relocate函数地址等操作后,就可以执行 ko 的 init 操作了,这样一个 ko 的加载流程就结束了。同时,init段会被释放掉,仅留下 core 段来运行。


参考自野火驱动开发教学文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值