driver: linux2.6 内核模块导出函数实例(EXPORT_SYMBOL)-wangchenxicool-ChinaUnix博客 http://blog.chinaunix.net/uid-23381466-id-3837650.html
内核版本:2.6.38-11-generic
内核自己都大量利用内核符号表导出函数,那么应该导出呢,ldd3上面说只需要EXPORT_SYMBOL一类的宏导出即可,结果试了很久都不行,最后查看文档,算是明白一点了。
对于导出符号表,内核文档给出了三种解决方案,见尾部,现在忽略。
现在有两个模块,a模块导出函数myprint,b模块使用该函数,想象一下如果a模块 EXPORT_SYMBOL(myprint) ,实际上b模块知道吗,很明显b模块对这件事情不是很清楚(这么说不是很准确),要调用a模块的myprint函数,需要知道myprint函数在内存中的位置,首先在内核符号表中是没有说明的,所以...
当我们编译完a模块后,看看有些什么文件,是不是有一个Module.symvers文件,打开看看什么状况?
0x705034f7 myprint /home/darren/Desktop/darren/print/myprint EXPORT_SYMBOL
好了,这一行对b模块来说已经足够了,指定了内存位置,符号名称,模块路径。最简单的方法就是把这个文件复制到b模块所在目录,然后编译就没有讨厌的错误了,可以正常insmod模块。这种方法是内核文档中提到的方法之一。
但是每次调用该函数都要复制一次,更糟糕的是a模块每编译一次,都要重新复制一次,为什么内核自己导出的函数我们可以直接用呢?现在就就解决:
编译内核的时候同样会生成一个Module.symvers文件,内核导出的所有符号都在里面,我们在编译模块的时候实际上会调用内核的顶层makefile,也就是说内核的Module.symvers对我们的模块是可见的,和我们自己的Module.symvers文件一样,OK,把a模块的Module.symvers文件合并到内核的Module.symvers文件中,这时候myprint函数就成了真正的导出函数了,其他的模块只需要生命一下就可以用了。
代码如下
a模块代码:
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/kernel.h>
-
-
MODULE_LICENSE("GPL");
-
int myprint(void)
-
{
-
printk("c");
-
return 0;
-
}
-
static int darren_init(void)
-
{
-
return 0;
-
}
-
static void darren_exit(void)
-
{
-
}
-
module_init(darren_init);
-
module_exit(darren_exit);
-
EXPORT_SYMBOL(myprint);
b模块代码:
-
#include <linux/seq_file.h>
-
#include <linux/cdev.h>
-
#include <asm/system.h>
-
-
MODULE_LICENSE("GPL");
-
extern int print(void);
-
static int darren_init(void)
-
{
-
int i=0;
-
printk("b module init\n");
-
for(;i<10;i++)print();
-
return 0;
-
}
-
static void darren_exit(void)
-
{
-
}
-
module_init(darren_init);
-
module_exit(darren_exit);
a模块的Makefile如下:
点击(此处)折叠或打开
-
NAME:=a
-
SYM:=/usr/src/linux-headers-2.6.38-8-generic/Module.symvers
-
DIR:=/lib/modules/$(shell uname -r)/build/
-
PWD:=$(shell pwd)
-
obj-m = $(NAME).o
-
build:
-
-
make -C $(DIR) M=$(PWD)
-
sudo chmod 777 $(SYM)
-
sudo sed -i '/myprint/d' $(SYM)
-
sudo cat Module.symvers>>$(SYM)
-
sudo chmod 644 $(SYM)
b模块的makefile:
点击(此处)折叠或打开
-
NAME:=b
-
DIR:=/lib/modules/$(shell uname -r)/build/
-
PWD:=$(shell pwd)
-
obj-m = $(NAME).o
-
build:
-
make -C $(DIR) M=$(PWD)
注意:路径/usr/src/linux-headers-2.6.38-8-generic/Module.symvers 有可能不对如果不行就改成/usr/src/linux-headers-`uname -r`-generic/Module.symvers
内核文档:
-
Sometimes, an external module uses exported symbols from
-
another external module. kbuild needs to have full knowledge of
-
all symbols to avoid spitting out warnings about undefined
-
symbols. Three solutions exist for this situation.
-
-
NOTE: The method with a top-level kbuild file is recommended
-
but may be impractical in certain situations.
-
-
Use a top-level kbuild file
-
If you have two modules, foo.ko and bar.ko, where
-
foo.ko needs symbols from bar.ko, you can use a
-
common top-level kbuild file so both modules are
-
compiled in the same build. Consider the following
-
directory layout:
-
-
./foo/ <= contains foo.ko
-
./bar/ <= contains bar.ko
-
-
The top-level kbuild file would then look like:
-
-
#./Kbuild (or ./Makefile):
-
obj-y := foo/ bar/
-
-
And executing
-
-
$ make -C $KDIR M=$PWD
-
-
will then do the expected and compile both modules with
-
full knowledge of symbols from either module.
-
-
Use an extra Module.symvers file
-
When an external module is built, a Module.symvers file
-
is generated containing all exported symbols which are
-
not defined in the kernel. To get access to symbols
-
from bar.ko, copy the Module.symvers file from the
-
compilation of bar.ko to the directory where foo.ko is
-
built. During the module build, kbuild will read the
-
Module.symvers file in the directory of the external
-
module, and when the build is finished, a new
-
Module.symvers file is created containing the sum of
-
all symbols defined and not part of the kernel.
-
-
Use "make" variable KBUILD_EXTRA_SYMBOLS
-
If it is impractical to copy Module.symvers from
-
another module, you can assign a space separated list
-
of files to KBUILD_EXTRA_SYMBOLS in your build file.
-
These files will be loaded by modpost during the
-
initialization of its symbol tables.
阅读(1363) | 评论(0) | 转发(0) |