EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名);
EXPORT_SYMBOL 和 EXPORT_SYMBOL_GPL 用于导出符号到内核符号表中(内核符号表可通过 ‘/proc/kallsyms’ 查看),导出的符号可以被其它模块调用,调用前需要先声明。
通过 EXPORT_SYMBOL 导出的符号可以被包含GPL许可权的模块和不包含GPL许可权的模块调用;
通过 EXPORT_SYMBOL_GPL 导出的符号只能被包含GPL许可权的模块调用,否则会报错 FATAL: modpost: GPL-incompatible module ***.ko uses GPL-only symbol '***'.
example:模块A导出符号,模块B使用符号,代码如下
A模块代码:
// A module
#include
#include
int add_integar(int a, int b)
{
return a + b;
}
EXPORT_SYMBOL(add_integar);
int sub_integar(int a, int b)
{
return a - b;
}
EXPORT_SYMBOL_GPL(sub_integar);
static int __init A_init(void)
{
printk(KERN_INFO "A enter\n");
return 0;
}
static void __exit A_exit(void)
{
printk(KERN_INFO "A exit\n");
}
module_init(A_init);
module_exit(A_exit);
MODULE_AUTHOR("TASK_RUNNING.\n");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("export symbol module.\n");
A模块makefile:
#A module makefile
KVERS = $(shell uname -r)
obj-m += A.o
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
A模块编译后,会生成Module.symvers文件,使用 cat Module.symvers可查看内容如下:
0x00000000 sub_integar /home/task_running/test/A/A EXPORT_SYMBOL_GPL
0x00000000 add_integar /home/task_running/test/A/A EXPORT_SYMBOL
当加载A模块时,符号会被导出到内核符号表,使用 grep integar /proc/kallsyms 可查看被导出的符号,使用root权限执行时,可以查看符号对应的地址,普通用户查看的地址为全0
0000000000000000 r __ksymtab_add_integar [A]
0000000000000000 r __kstrtab_add_integar [A]
0000000000000000 r __ksymtab_sub_integar [A]
0000000000000000 r __kstrtab_sub_integar [A]
0000000000000000 T add_integar [A]
0000000000000000 t sub_integar [A]
B模块代码:
// B module
#include
#include
//此处需要用extern声明外部符号
extern int add_integar(int a, int b);
extern int sub_integar(int a, int b);
static int __init B_init(void)
{
printk(KERN_INFO "B module enter\n");
printk(KERN_INFO "ADD = %d\n", add_integar(5, 6));
printk(KERN_INFO "SUB = %d\n", sub_integar(6, 5));
return 0;
}
static void __exit B_exit(void)
{
printk(KERN_INFO "B module exit\n");
}
module_init(B_init);
module_exit(B_exit);
MODULE_AUTHOR("TASK_RUNNING.\n");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("use symbol module.\n");
B模块makefile:
#B module makefile
KVERS = $(shell uname -r)
obj-m += B.o
build:kernel_modules
#此处需要指定A模块编译后生成的Module.symvers文件
KBUILD_EXTRA_SYMBOLS += /home/task_running/test/A/Module.symvers
export KBUILD_EXTRA_SYMBOLS
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
B模块必须在A模块加载后才能使用A模块的符号,加载B模块后,使用 dmesg 可以查看内核打印的信息。