linux 内核中EXPORT_SYMBOL()分析与实践

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函数。
image


本文完!!!

posted on 2021-11-01 21:36  Iriczhao  阅读(1419)  评论(0编辑  收藏  举报

导航

Live2D