本文共 4550 字,大约阅读时间需要 15 分钟。
Linux设备驱动开发详解-第4章(三)-导出符号
EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。
2.6就必须用EXPORT_SYMBOL()来导出来(因为2.6默认不到处所有的符号)。
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连接上。
本文将编写两个模块来验证导出符号。
第一个是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. All Rights Reserved.======================================================================*/#include #include #include 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]
(1)import _symb.c文件
/*======================================================================A simple kernel module to introduce export symbol The initial developer of the original code is Baohua Song. All Rights Reserved.======================================================================*/#include #include #include 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
(1)本例中因为export_symb是被调用者,所以当其被调用时,export_symb不能被卸载,只有在未被调用的情况下才能卸载。
(2)import_symb需要调用export_symb,所以加载import_symb之前先要加载export_symb模块。 (3)EXPORT_SYMBOL在内核中是经常出现的。转载地址:http://oifqj.baihongyu.com/