Linux kernel module symbols relocation

尝试回答两个问题:

1. Module如何解决kernel的函数调用问题

2. Module如何解决使用到其它module的函数调用问题


*.ko是个ELF文件,本质上与跑在user space的APP一样. 从Module编译结果看起:

执行指令: readelf -a usb_wwan.ko,摘录部分与本主题有关系:

00002104  0001801c R_ARM_CALL        00000000   printk
0000210c  00018b1c R_ARM_CALL        00001014   usb_serial_get_by_inde

 与printk不一样, usb_serial_get_by_inde来自于usbserial.ko,但是二者在usb_wwan.ko并无值得关注的差别,也就是说此刻,usb_wwan.ko并没区分它所调用的函数来自于何方


那加载usb_wwan.ko的时候,kernel做了些什么事情呢?

load_module干的活太多,我们还是只关注relocation相关细节, simplify_symbols()完成了symbols的处理,看具体细节

load_module() --> simplify_symbols()

case SHN_UNDEF:
			ksym = resolve_symbol_wait(mod, info, name);
SHN_UNDEF处理了kernel及其他模块的符号,go on...

simplify_symbols() -->resolve_symbol_wait()-->resolve_symbol() -->find_symbol()-->each_symbol_section()

bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
				    struct module *owner,
				    void *data),
			 void *data)
{
	struct module *mod;
	static const struct symsearch arr[] = {
		{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
		  NOT_GPL_ONLY, false },
		{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
		  __start___kcrctab_gpl,
		  GPL_ONLY, false },
		{ __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
		  __start___kcrctab_gpl_future,
		  WILL_BE_GPL_ONLY, false },
#ifdef CONFIG_UNUSED_SYMBOLS
		{ __start___ksymtab_unused, __stop___ksymtab_unused,
		  __start___kcrctab_unused,
		  NOT_GPL_ONLY, true },
		{ __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
		  __start___kcrctab_unused_gpl,
		  GPL_ONLY, true },
#endif
	};//Kernel EXPORT_SYMBOL

        //所以,下面是在kernel的符号表里搜索,找到了就高高兴兴的返回
	if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
		return true;

        //modules是所有已加载的module的表头,所以开始苦逼的一个模块一个模块的寻找了
	list_for_each_entry_rcu(mod, &modules, list) {
		struct symsearch arr[] = {
			{ mod->syms, mod->syms + mod->num_syms, mod->crcs,
			  NOT_GPL_ONLY, false },
			{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
			  mod->gpl_crcs,
			  GPL_ONLY, false },
			{ mod->gpl_future_syms,
			  mod->gpl_future_syms + mod->num_gpl_future_syms,
			  mod->gpl_future_crcs,
			  WILL_BE_GPL_ONLY, false },
#ifdef CONFIG_UNUSED_SYMBOLS
			{ mod->unused_syms,
			  mod->unused_syms + mod->num_unused_syms,
			  mod->unused_crcs,
			  NOT_GPL_ONLY, true },
			{ mod->unused_gpl_syms,
			  mod->unused_gpl_syms + mod->num_unused_gpl_syms,
			  mod->unused_gpl_crcs,
			  GPL_ONLY, true },
#endif
		};
                //得之,我幸
		if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
			return true;
	}
	return false;//不得,我命,报错吧
}

符号处理完了,下部就是动真格的地址替换了

load_module() -->apply_relocations()-->apply_relocate()

apply_relocate()是个架构相关的函数.


至于post_relocation(), 就是宣告下,大概像什么事情都办完了,可以去民政局领证的意思吧,呵呵


结论:

module对于来自kernel或者来自其他module的函数处理方法一致. module.c帮忙处理了这部分差异. 而load_module真的是劳苦功高,脏活累活都干完了,只要这个函数执行完,新加载的module就跟built in的东西,一样一样的了

你可能感兴趣的:(Android,BSP)