$ readelf -h hello.ko
ELF Header:
Magic: 7f 45 4c 46020101000000000000000000 Class: ELF64
Data: 2's complement, little endian
Version: 1(current) OS/ABI: UNIX - System V
ABI Version: 0 Type: REL (Relocatable file) Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0(bytes into file) Start of section headers: 2904(bytes into file) Flags: 0x0
Size of this header: 64(bytes) Size of program headers: 0(bytes) Number of program headers: 0 Size of section headers: 64(bytes) Number of section headers: 19 Section header string table index: 18
/* This is where the real work happens */SYSCALL_DEFINE3(init_module, void __user *, umod,
unsignedlong, len, constchar __user *, uargs)
{
struct module *mod;
int ret =0;
/* Do all the hard work */ mod =load_module(umod, len, uargs); //模块加载
/* Start the module */if (mod->init != NULL)
ret =do_one_initcall(mod->init);//模块init函数调用
//...
return0;
}
/* Allocate and load the module: note that size of section 0 is always
zero, and we rely on this for optional sections. */staticstruct module *load_module(void __user *umod,
unsignedlong len,
constchar __user *uargs)
{
struct load_info info = { NULL, };
struct module *mod;
long err;
/* Copy in the blobs from userspace, check they are vaguely sane. */ err =copy_and_check(&info, umod, len, uargs); // 拷贝到内核
if (err)
returnERR_PTR(err);
/* Figure out module layout, and allocate all the memory. */ mod =layout_and_allocate(&info); // 地址空间分配
if (IS_ERR(mod)) {
err =PTR_ERR(mod);
goto free_copy;
}
/* Fix up syms, so that st_value is a pointer to location. */ err =simplify_symbols(mod, &info); // 符号解析
if (err <0)
goto free_modinfo;
err =apply_relocations(mod, &info); // 重定位
if (err <0)
goto free_modinfo;
//...
}
函数 load_module 内有四个关键的函数调用:
copy_and_check 将模块从用户空间拷贝到内核空间
layout_and_allocate 为模块进行地址空间分配
simplify_symbols 为模块进行符号解析
apply_relocations 为模块进行重定位
由此可见,模块加载时,内核为模块文件 hello.ko 进行了链接的过程。
至于函数 do_one_initcall 的实现就比较简单了,即调用了模块的入口函数 init。
1
2
3
4
5
6
7
8
9
10
11
12
13
int __init_or_module do_one_initcall(initcall_t fn)
{
int count =preempt_count();
int ret;
if (initcall_debug)
ret =do_one_initcall_debug(fn);
else ret =fn(); //调用init module
//...
return ret;
}
SYSCALL_DEFINE2(delete_module, constchar __user *, name_user,
unsignedint, flags)
{
struct module *mod;
char name[MODULE_NAME_LEN];
int ret, forced =0;
//...
/* Final destruction now no one is using it. */if (mod->exit != NULL)
mod->exit(); //调用exit module
free_module(mod);//卸载模块
//...
}