现在的位置: 首页 > 综合 > 正文

Linux内核一个模块调另一个模块的函数

2013年09月04日 ⁄ 综合 ⁄ 共 4061字 ⁄ 字号 评论关闭

  前几天,需要在一个内核模块A中添加一个新功能。这个新功能用到了另一个内核模块B中的函数C。我将相关的头文件include之后,加载A模块时,总是出错,说用到的那个函数C找不着。

  怎么回事?以前没接触过内核编程的,找了个小牛问了一下,原来是Linux2.6内核不会自动的将非static 函数和变量导入到kernel 空间,需要用到EXPORT_SYMBOL来对函数做一下标记才行。

 /* in module B*/

void C()

{

......

}

EXPORT_SYMBOL(C);

/*in module A*/

void func_in_A()

{

    extern void c(void);

    ......

    C();

   ......

}

OK了,这下子编译的时候,虽然还会报warning(不报才怪了),但是insmod时,不会出错了。

上网上找了找别人写的这方面的文章,贴到下面,用得着的朋友,都看看吧,也不用到处找了

一个模块mod1中定义一个函数func1;在另外一个模块mod2中定义一个函数func2,func2调用func1。
在模块mod1中,EXPORT_SYMBOL(func1);
在模块mod2中,extern int func1();
就可以在mod2中调用func1了。

=================================

EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。
2.6就必须用EXPORT_SYMBOL() 来导出来(因为2.6默认不到处所有的符号)。

1、EXPORT_SYMBOL的作用是什么?
EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。
这里要和System.map做一下对比:
System.map 中的是连接时的函数地址。连接完成以后,在2.6内核运行过程中,是不知道哪个符号在哪个地址的。
EXPORT_SYMBOL 的符号, 是把这些符号和对应的地址保存起来,在内核运行的过程中,可以找到这些符号对应的地址。而模块在加载过程中,其本质就是能动态连接到内核,如果在模块中引用了内核或其它模块的符号,就要EXPORT_SYMBOL这些符号,这样才能找到对应的地址连接。

2、使用方法
   第一、在模块函数定义之后使用EXPORT_SYMBOL(函数名)
   第二、在掉用该函数的模块中使用extern对之声明
   第三、首先加载定义该函数的模块,再加载调用该函数的模块

另外,在编译调用某导出函数的模块时,往往会有WARNING: "****" [**********] undefined!
使用dmesg命令后会看到相同的信息。开始我以为只要有这个错误就不能加载模块,后来上网查了一下,发现这主要是因为在编译连接的时候还没有和内核打交道,当然找不到symbol了,但是由于你生成的是一个内核模块,所以LD不提示error,而是给出一个warning,寄希望于在insmod的时候,内核能够把这个symbol连接上。

参考资料:

-------------------------------------------------------------

http://blog.chinaunix.net/u/12592/showart_461504.html

一个模块mod1中定义一个函数func1;在另外一个模块mod2中定义一个函数func2,func2调用func1。
在模块mod1中,EXPORT_SYMBOL(func1);
在模块mod2中,extern int func1();
就可以在mod2中调用func1了。

参考:
http://topic.csdn.net/u/20070910/09/ee2cff13-9179-41e3-9292-4fd73261f709.html
http://www.dev-archive.com/msdn-archive/524/kernel-driver-5244619.shtm

mod1.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>

static int func1(void)
{
        printk("In Func: %s...\n",__func__);
        return 0;
}

EXPORT_SYMBOL(func1);

static int __init hello_init(void)
{
        printk("Module 1,Init!\n");
        return 0;
}

static void __exit hello_exit(void)
{
        printk("Module 1,Exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);

#############################################################
mod2.c
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>

static int func2(void)
{
        extern int func1(void);
        func1();
        printk("In Func: %s...\n",__func__);
        return 0;
}

static int __init hello_init(void)
{
        printk("Module 2,Init!\n");
        func2();
        return 0;
}

static void __exit hello_exit(void)
{
        printk("Module 2,Exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);

################################################################
Makefile
ifneq ($(KERNELRELEASE),)
obj-m   := XXXX.o
else
KDIR    := /lib/modules/$(shell uname -r)/build
PWD             := $(shell pwd)

default:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
        rm -rf Module.symvers *.ko *.o *.mod.c .*.cmd .tmp_versions

endif

################################################################

#insmod ./mod1.ko
#insmod ./mod2.ko
#rmmod mod2
#rmmod mod1

Jan 11 11:59:17 wangyao-desktop kernel: [ 9886.801010] Module 2,Exit!
Jan 11 11:59:21 wangyao-desktop kernel: [ 9891.450214] Module 1,Exit!
Jan 11 12:05:29 wangyao-desktop kernel: [10258.385014] Module 1,Init!
Jan 11 12:05:38 wangyao-desktop kernel: [10267.465923] Module 2,Init!
Jan 11 12:05:38 wangyao-desktop kernel: [10267.465928] In Func: func1...
Jan 11 12:05:38 wangyao-desktop kernel: [10267.465930] In Func: func2...
Jan 11 12:05:50 wangyao-desktop kernel: [10280.091755] Module 2,Exit!
Jan 11 12:05:57 wangyao-desktop kernel: [10287.332596] Module 1,Exit!

可见,在mod2中的func2函数成功的调用了mod1中的func1函数。

注意:
在编译mod2的时候,出现一个WARNING:
root@wangyao-desktop:~/modules/export_symbol/mod2# make
make -C /lib/modules/2.6.22-14-generic/build SUBDIRS=/root/modules/export_symbol/mod2 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.22-14-generic'
Building modules, stage 2.
MODPOST 1 modules
WARNING: "func1" [/root/modules/export_symbol/mod2/mod2.ko] undefined!
make[1]: Leaving directory `/usr/src/linux-headers-2.6.22-14-generic'

这主要是因为在编译连接的时候还没有和内核打交道,当然找不到symbol了,但是由于你生成的是一个内核模块,所以LD不提示error,而是给出一个warning,寄希望于在insmod的时候,内核能够把这个symbol连接上。

抱歉!评论已关闭.