linux 内核中EXPORT_SYMBOL()分析与实践
linux内核版本 | 时间 | 备注 |
---|---|---|
4.1.15 | 2021/11/1 | 技术总结 |
一、EXPORT_SYMBOL()分析
EXPORT_SYMBOL实际是一个宏函数。用于将函数或者符号向全部内核代码公开,不用修改内核代码就可以在内核模块中直接调用(注意是在内核模块中),即:使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。
定义如下://出自 linux dir/include/linux/export.h文件
#define __EXPORT_SYMBOL(sym, sec) \
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"), aligned(1))) \
= VMLINUX_SYMBOL_STR(sym); \
extern const struct kernel_symbol __ksymtab_##sym; \
__visible const struct kernel_symbol __ksymtab_##sym \
__used \
__attribute__((section("___ksymtab" sec "+" #sym), unused)) \
= { (unsigned long)&sym, __kstrtab_##sym }
#define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "")
这里以EXPORT_SYMBOL(system_state)为例,经过宏替换后结果如下:
extern typeof (system_state) system_state;
extern __visible void *__crc_system_state __attribute__ ((weak));
static const unsigned long __kcrctab_system_state __used __attribute__ ((section("___kcrctab" sec "+" #sym), unused)) = (unsigned long) &__crc_system_state;
static const char __kstrtab_system_state[] __attribute__((section("__ksymtab_strings"), aligned(1))) = "system_state";
extern const struct kernel_symbol __ksymtab_system_state;
__visible const struct kernel_symbol __ksymtab_system_state __used __attribute__ ((section("___ksymtab" sec "+" #sym), unused)) = {(unsigned long)&system_state,__kstrtab_system_state};
以上代码实则是:对于每个使用EXPORT_SYMBOL()导出的符号,都将在ksymtab节中放置一个与之关联的结构体。
二、实践过程记录
创建一个module_first模块和module_second模块,再创建一个makefile文件。
//module_first.c 文件
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
static int module_first_function(void)
{
printk("this is module_first_function\r\n");
return 0;
}
EXPORT_SYMBOL(module_first_function); /*导出module_first_function函数供module_second模块使用 */
static int __init module_first_init(void)
{
printk("module_first_init\r\n");
return 0;
}
static int __exit module_first_exit(void)
{
printk("module_first_exit\r\n");
return 0;
}
// 指定驱动的入口函数和出口函数
module_init(module_first_init);
module_exit(module_first_exit);
MODULE_AUTHOR("iriczhao");
MODULE_LICENSE("GPL");
//module_second.c 文件
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
extern int module_first_function(void);
static int module_second_function(void)
{
/* 此处调用module_first模块中module_first_function函数 */
module_first_function();
printk("============================\r\n");
printk("this is module_second_function\r\n");
printk("============================\r\n");
return 0;
}
static int __init module_second_init(void)
{
printk("module_second_init\r\n");
module_second_function();
return 0;
}
static int __exit module_second_exit(void)
{
printk("module_second_exit\r\n");
return 0;
}
// 指定驱动的入口函数和出口函数
module_init(module_second_init);
module_exit(module_second_exit);
MODULE_AUTHOR("iriczhao");
MODULE_LICENSE("GPL");
#makefile 文件
KERNELDIR := /home/iriczhao/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga
CURRENT_PATH := $(shell pwd)
obj-m := module_first.o module_second.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
编译构建后,将生成的module_first.ko和module_second.ko两个模块文件拷贝到运行环境根文件系统中。加载模块,运行结果如下:
可见,根据上图红框中内容显示,在module_second模块中成功调用了module_first模块中使用EXPORT_SYMBOL声明的module_first_function函数。
本文完!!!