流程图
模块数据的拷贝过程
首先从磁盘上打开,然后将文件fd传给内核,内核会将模块文件的内容拷贝到一个通过vmalloc分配的临时虚拟内存中,执行完一些检查后,再将模块内容拷贝到最终的虚拟内存中,然后进行重定位。最后的这块虚拟内存可以通过module_alloc也可以通过vzalloc分配,一般会调用module_alloc来分配。module_alloc又调用了__vmalloc_node_range
,__vmalloc_node_range
可以设置分配的虚拟地址区域的范围,下面是x86上的实现:
这里对虚拟地址的范围做了限制:MODULES_VADDR + get_module_load_offset() ~ MODULES_END
,如果不考虑地址随机化(CONFIG_RANDOMIZE_BASE),get_module_load_offset的返回值就是0,所以范围是MODULES_VADDR ~ MODULES_END
。其中涉及到的宏的定义如下:
#define __START_KERNEL_map _AC(0xffffffff80000000, UL) #define KERNEL_IMAGE_SIZE (512 * 1024 * 1024) #define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) #define MODULES_END _AC(0xfffffffffe000000, UL)
所以最终模块所在的虚拟地址范围是0xffffffff80000000 ~ 0xfffffffffe000000
,长度为512MB,具体可以参考x86_64虚拟地址空间布局。