当你在写内核模块时,会出现很多令人沮丧的问题,现在针对编译模块时常出现的问题做以下总结并给出相应解决方法。
最常见的问题是make时出现错误提示,如果自己的模块仅仅是调用内核里面的函数,就要根据具体错误提示找原因,
比如头文件是否添加完整,函数返回值是否正确,参数类型有没有变动等等。这些都是比较容易解决的。
还有一种情况就是一个模块调用另外一个模块的导出函数,明明自己在插入模块A时导出了函数,然后使用模块B时
调用A的导出函数就是出现错误,这种情况该怎么解决?最简单的方法是加载模块A成功之后会生成一个
Module_symvers文件,你可以把这个文件直接拷贝到模块B下,然后编译就会通过。Module_symvers文件里面
主要是模块A里面导出函数与符号地址。还有一种迫不得已的办法就是通过cat /proc/kallsyms | grep
xxx,其中xxx
为导出函数的名称,现举例。要获得函数crypto_alloc_base的符号地址。
$cat /proc/kallsyms | grep crypto_alloc_base
c03603a0 T crypto_alloc_base
c07f7234 r __ksymtab_crypto_alloc_base
c07feb5c r __kcrctab_crypto_alloc_base
c0809bc8 r __kstrtab_crypto_alloc_base
c03603a0 u
crypto_alloc_base [example_test]
这里要注意,后面出现了T,r等标志,接下来说明下各标志的含义
T The symbol
is in the text(code) section
D The symbol is in the
initialized data section
R The sysbol is in a read only data section
t static
d static
R const
r static const
获取地址c03603a0,定义一个long unsigned int crypto_alloc_base_address =
0xc03603a0,然后把这个变量
强制类型转换为我们需要的类型,struct crypto_tfm *crypto_alloc_base = (struct
crypto_tfm *)crypto_alloc_base_address就可以使用该函数了。
如果上述方法还不奏效,且你引用的模块相对独立可以直接把需要的函数完整拷贝过来进行处理。
还有一种方法,当你在模块A中导出函数之后,在模块B中可以使用extern进行声明使用的函数是文件外部的函数,
具体使用方法是:比如说模块A的导出了函数int read(int fd,void *buf,size_t
count)。在模块B中要调用A中的导出
函数可以直接声明extern int read(int ,void *,size_t)就OK了。
接下来进行加载时会出现的问题主要有:1、加载模块已经存在,说明之前已经加载了该模块,可以先卸载,再重新加载。
2、该操作不允许或者没有权限,这时如果不是由于没有使用root,就要使用dmesg打印出结果以便查看哪里出现
了问题。
卸载模块时出现的问题比较少,主要是对模块进行卸载时显示模块正在使用,这样你又急着卸载,可以通过重新启动
机器解决问题。上面只是不是办法的办法,出现上述情况多数是因为使用了带参数的模块,而在定义参数时没有初始化,刚好插入模块时忘记带参数,这样就导致了模块确实加载了,但是加载出错。不能正常卸载。预防这种情况的最好方式是对带参模块进行初始化,这样即便是加载模块时没有输入参数,也不会给卸载模块带来麻烦。
也可以通过$sudo rmmod -f xxx或 $sudo
rmmod -w xxx。其中f的含义为 forces a module unload, and
may crash your machine. This requires the Forced Module Removal option
when the kernel was compiled.
这样强制删除模块有可能使机器荡机。w的含义是begins
a module removal even if it is used and will stop new users from
accessing the module (so it should eventually fall to
zero).它主要是去掉对这个模块的引用数量达到这个
模块可以卸载。但是上述两种方法有时很难奏效。