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

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

linux内核版本时间备注
4.1.152021/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函数。


本文完!!!

在编译Linux内核模块时,EXPORT_SYMBOL用于将模块定义的符号(函数、变量等)导出到内核空间,以便其他模块或内核代码可以使用这些符号。 以下是在编译ko驱动时使用EXPORT_SYMBOL的步骤: 1. 在驱动程序定义需要导出的符号,例如: ```c #include <linux/module.h> #include <linux/kernel.h> void my_function(void) { printk(KERN_INFO "My function called\n"); } EXPORT_SYMBOL(my_function); ``` 在上述例子,my_function函数被定义并使用EXPORT_SYMBOL宏导出。 2. 编写Makefile文件以编译驱动程序,例如: ``` obj-m += my_driver.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean ``` 在上述例子,Makefile文件使用obj-m变量定义要编译的模块名,并使用make命令编译模块。 3. 在终端执行make命令编译驱动程序,例如: ``` $ make ``` 4. 加载驱动程序,例如: ``` $ insmod my_driver.ko ``` 在上述例子,使用insmod命令加载my_driver.ko驱动程序。 5. 卸载驱动程序,例如: ``` $ rmmod my_driver ``` 在上述例子,使用rmmod命令卸载my_driver驱动程序。 需要注意的是,EXPORT_SYMBOL用于将符号导出到内核空间,因此只能在内核模块使用。如果导出的符号是GPL协议的,应该使用EXPORT_SYMBOL_GPL宏。如果导出的符号是GPL或者可能在未来被GPL要求的,应该使用EXPORT_SYMBOL_GPL_FUTURE宏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值