您的位置:首页 > 运维架构 > Linux

Linux设备驱动开发详解-第4章(三)-导出符号

2011-10-24 17:15 309 查看
Linux设备驱动开发详解-第4章(三)-导出符号
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连接上。

3 实例验证

本文将编写两个模块来验证导出符号。

第一个是export_symb.c,这个模块是一个导出整数加、减运算函数符号的内核模块的例子(这些导出符号没有实际意义,只是为了演示)。

第二个模块是import_ symb.c,这个模块调用export_symb的导出符号。

3.1 export_symb.c模块

(1)export_symb.c文件

/*======================================================================
A simple kernel module to introduce export symbol

The initial developer of the original code is Baohua Song
<author@linuxdriver.cn>. All Rights Reserved.
======================================================================*/
#include <linux/init.h>
#include<linux/kernel.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

int add_integar(int a,int b)
{
printk(KERN_INFO "add_integar\n");
return a+b;
}

int sub_integar(int a,int b)
{
printk(KERN_INFO "sub_integar\n");
return a-b;
}

EXPORT_SYMBOL(add_integar);
EXPORT_SYMBOL(sub_integar);
static int __init export_symb_init(void)
{
printk(KERN_INFO "export_symb,Init!\n");
return 0;
}

static void __exit export_symb_exit(void)
{
printk(KERN_INFO "export_symb,Exit!\n");
}

module_init(export_symb_init);
module_exit(export_symb_exit);

MODULE_AUTHOR("Minghua");
MODULE_DESCRIPTION("export_symb export");
MODULE_ALIAS("export_symb ");


(2)Makefile文件

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

default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
#endif

clean:
rm -f*.ko *.mod.c *.mod.o *.o *.markers *.order *.symvers


(3)编译和加载

[root@localhost export_symb]# make
[root@localhost export_symb]# insmod export_symb.ko
[root@localhost export_symb]# dmesg | tail -2
export_symb,Exit!
export_symb,Init!

从“/proc/kallsyms”文件中找出add_integar、sub_integar 相关信息:
[root@localhost export_symb]# cat /proc/kallsyms | grep integar
f7fde0bc r __ksymtab_sub_integar	[export_symb]
f7fde0cc r __kstrtab_sub_integar	[export_symb]
f7fde0c4 r __ksymtab_add_integar	[export_symb]
f7fde0d8 r __kstrtab_add_integar	[export_symb]
f7fde01e T add_integar	[export_symb]
f7fde000 T sub_integar	[export_symb]

3.2 import_ symb.c模块

(1)import _symb.c文件

/*======================================================================
A simple kernel module to introduce export symbol

The initial developer of the original code is Baohua Song
<author@linuxdriver.cn>. All Rights Reserved.
======================================================================*/
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

extern int add_integar(int a,int b);
extern int sub_integar(int a,int b);

static void func2(void)
{
int temp = 0;

temp =  add_integar(10,5);
printk(KERN_INFO "add_integar(10,5) =  %d \n", temp);

temp =  sub_integar(10,5);
printk(KERN_INFO "sub_integar(10,5) =  %d \n",temp);
temp =  sub_integar(10,5);
printk(KERN_INFO "sub_integar(10,5) =  %d \n",temp);
}

static int __init import_symb_init(void)
{
printk(KERN_INFO "Import_symb,Init!\n");
func2();
return 0;
}

static void __exit import_symb_exit(void)
{
printk(KERN_INFO "Import_symb,Exit!\n");
}

module_init(import_symb_init);
module_exit(import_symb_exit);

MODULE_AUTHOR("Minghua");
MODULE_DESCRIPTION("import_symb call");
MODULE_ALIAS("import_symb ");


(2)Makefile文件
#ifneq ($(KERNELRELEASE),)
obj-m := import_symb.o
#else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
#endif

clean:
rm -f *.ko *.mod.c *.mod.o *.o *.markers *.order *.symvers


(3)编译和加载

[root@localhost import_symb]# make
[root@localhost import_symb]# insmod import_symb.ko
[root@localhost import_symb]# dmesg | tail -5
Import_symb,Init!
add_integar
add_integar(10,5) =  15
sub_integar
sub_integar(10,5) =  5


4 扩展

(1)本例中因为export_symb是被调用者,所以当其被调用时,export_symb不能被卸载,只有在未被调用的情况下才能卸载。

(2)import_symb需要调用export_symb,所以加载import_symb之前先要加载export_symb模块。

(3)EXPORT_SYMBOL在内核中是经常出现的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: