最近买了个手机乐视1pro,没有内核源码,想插入一些自己编译的模块来扩展内核,于是找到了硬件相近的一加2的内核源码,把编译得到的模块拷到手机上,发现无法加载。经过摸索,发现原因是内核开启了CONFIG_MODVERSIONS,但是没开启CONFIG_MODULE_FORCE_LOAD. 内核symbol有crc校验,不同源码树编译出来的内核,symbol的crc可能不一样。
要想编译出crc一致的模块,需要用到编译内核时生成的Module.symvers这个文件,厂商没有开放内核源码,更不可能提供这个文件给你了。不过,既然内核会对模块引用到的symbol验证crc,说明内核本身就保存有一份crc,我们只要提取出来就行了。
我们只要编写如下模块,就可完成提取工作:
symcrc.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/string.h>
#include <linux/slab.h>
static char symcrc[256];
static ssize_t symcrc_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)
{
const struct kernel_symbol *ksymbol;
char *symname;
struct module *owner;
const unsigned long *crc = NULL;
bool gplok = true;
bool warn = true;
symname = kstrndup(_buf,strlen(_buf)-1,GFP_KERNEL);
ksymbol = find_symbol (symname, &owner, &crc, gplok, warn);
if (ksymbol != NULL && crc != NULL)
snprintf (symcrc, ARRAY_SIZE(symcrc), "0x%lx\t%s\tvmlinux\tEXPORT_SYMBOL\n", *crc, ksymbol->name);
else{
symcrc[0] = '\0';
}
kfree(symname);
return _count;
}
static ssize_t symcrc_read(struct class *cls, struct class_attribute *attr, char *_buf)
{
return sprintf(_buf, "%s", symcrc);
}
static struct class *sym