1.什么是符号?
主要是指全局变量和函数
2.为什么要导出符号?
linux内核采用的是模块化的形式管理内核代码。内核中每个模块之间是相互独立的,也就是说A模块的全局变量和函数,B模块是无法访问的。若B模块想要使用A模块中的已有符号,那么必须将A模块中的符号做符号导出,导出到模块符号表中,然后B模块可以使用A模块导出的符号。
3.如何导出符号?
linux内核给我们提供了两个函数宏,用他们做符号导出。
3.1 EXPORT_SYMBOL(符号)
3.2 EXPORT_SYMBOL_GPL(符号)
4.符号表的类型
4.1 本地符号表
用户自定义模块导出的符号表,这些符号表保存在本模块目录下Module.symvers
4.2 全局符号表
内核已经导出的符号表,在 /proc/kallsyms
sudo cat /proc/kallsyms |grep printk 0xc15cd833
5.注意
安装时,先安装符号导出模块,再安装使用符号的模块;
卸载时,先卸载使用符号的模块,再卸载导出符号的模块。
6.测试
6.1 测试思路
分别创建两个驱动模块文件夹,分别编写符号导出驱动模块(helloa.c)和符号使用驱动模块(hellob.c)。
在helloa.c中使用EXPORT_SYMBOL()宏函数和EXPORT_SYMPOL_GPL()宏函数测试导出符号。
编译helloa.c会生成本地符号表Module.symvers。
将生成的本地符号表Module.symvers拷贝到hellob驱动模块文件夹下,编译hellob.c。
查看内核打印消息
验证对错
6.2 本地符号表符号导出实际操作
创建文件夹,每个文件夹下有一个.c源码和Makefile工程管理文件
helloa.c
#include <linux/init.h>
#include <linux/module.h>
int num = 100;
void show(void)
{
printk("aaaa: num =%d \n",num);
}
static int hello_init(void)
{
printk("hello_init \n");
return 0;
}
static void hello_exit(void)
{
printk("hello_exit \n");
return;
}
EXPORT_SYMBOL(num);
EXPORT_SYMBOL(show);
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cfy");
Makefile
ifneq ($(KERNELRELEASE),)
$(info "2nd")
obj-m:=helloa.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
endif
clean:
rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order
Makefile
ifneq ($(KERNELRELEASE),)
$(info "2nd")
obj-m:=helloa.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
endi
clean:
rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order
hellob.c
#include <linux/init.h>
#include <linux/module.h>
extern int num;
extern void show(void);
static int hello_init(void)
{
printk("hello_init %d\n",num);
show();
return 0;
}
static void hello_exit(void)
{
printk("hello_exit \n");
return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cfy");
Makefile
ifneq ($(KERNELRELEASE),)
$(info "2nd")
obj-m:=hellob.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
KBUILD_EXTRA_SYMBOLS += /home/lwj/driver/code-final/02export/a/Module.symvers
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
endif
clean:
rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order
编译helloa.c
生成Module.symvers
将Module.symvers拷贝到b下
编译hellob.c,出现了未定义的问题。
参考https://blog.csdn.net/a834605978/article/details/125648701,找到了解决方法
修改hellob的Makefile,添加了第10行,注意要在make modules命令之后加载,一开始在之前加载,发现问题依然存在
ifneq ($(KERNELRELEASE),)
$(info "2nd")
obj-m:=hellob.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
KBUILD_EXTRA_SYMBOLS += /home/lwj/driver/code-final/02export/a/Module.symvers
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
endif
KBUILD_EXTRA_SYMBOLS += /home/lwj/driver/code-final/02export/a/Module.symvers
clean:
rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order
重新编译
安装导出模块
可以看到驱动模块可以正常安装,dmesg有打印信息
安装hellob模块
可以看到hellob驱动模块已经成功加载了helloa驱动模块中的全局变量num和全局函数show