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

来源:互联网 发布:智业软件 上市 编辑:程序博客网 时间:2024/06/05 19:17

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#elseKERNELDIR := /lib/modules/$(shell uname -r)/buildPWD := $(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 -2export_symb,Exit!export_symb,Init!

从“/proc/kallsyms”文件中找出add_integar、sub_integar 相关信息:

[root@localhost export_symb]# cat /proc/kallsyms | grep integarf7fde0bc 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#elseKERNELDIR := /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules#endifclean: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 -5Import_symb,Init!add_integaradd_integar(10,5) =  15 sub_integarsub_integar(10,5) =  5

4 扩展

       (1)本例中因为export_symb是被调用者,所以当其被调用时,export_symb不能被卸载,只有在未被调用的情况下才能卸载。
       (2)import_symb需要调用export_symb,所以加载import_symb之前先要加载export_symb模块。
       (3)EXPORT_SYMBOL在内核中是经常出现的。












原创粉丝点击