Linux EXPORT_SYMBOL

本文详细介绍了Linux内核中EXPORT_SYMBOL的功能及使用方法,包括如何在不同模块间导出和调用函数,以及在2.4与2.6内核版本间的区别。

一个模块mod1中定义一个函数func1;在另外一个模块mod2中定义一个函数func2,func2调用func1。
在模块mod1中,EXPORT_SYMBOL(func1);
在模块mod2中,extern int func1();
就可以在mod2中调用func1了。

=================================

EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。
2.6就必须用EXPORT_SYMBOL() 来导出来(因为2.6默认不到处所有的符号)。

1、EXPORT_SYMBOL的作用是什么?
EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。
这里要和System.map做一下对比:
System.map 中的是连接时的函数地址。连接完成以后,在2.6内核运行过程中,是不知道哪个符号在哪个地址的。
EXPORT_SYMBOL的符号,是把这些符号和对应的地址保存起来,在内核运行的过程中,可以找到这些符号对应的地址。而模块在加载过程中,其本质就是能动态连接到内核,如果在模块中引用了内核或其它模块的符号,就要EXPORT_SYMBOL这些符号,这样才能找到对应的地址连接。

2、使用方法
   第一、在模块函数定义之后使用EXPORT_SYMBOL(函数名)
   第二、在掉用该函数的模块中使用extern对之声明
   第三、首先加载定义该函数的模块,再加载调用该函数的模块

另外,在编译调用某导出函数的模块时,往往会有WARNING: "****" [**********] undefined!
使用dmesg命令后会看到相同的信息。开始我以为只要有这个错误就不能加载模块,后来上网查了一下,发现这主要是因为在编译连接的时候还没有和内核打交道,当然找不到symbol了,但是由于你生成的是一个内核模块,所以LD不提示error,而是给出一个warning,寄希望于在insmod的时候,内核能够把这个symbol连接上。

 

 

Linux内核头文件提供了一个方便的方法用来管理符号的对模块外部的可见性,因此减少了命名空间的污染(命名空间的名称可能会与内核其他地方定义的名称冲突),并且适当信息隐藏。 如果你的模块需要输出符号给其他模块使用,应当使用下面的宏定义:
EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);
这两个宏均用于将给定的符号导出到模块外. _GPL版本的宏定义只能使符号对GPL许可的模块可用。 符号必须在模块文件的全局部分导出,不能在函数中导出,这是因为上述这两个宏将被扩展成一个特殊用途的声明,而该变量必须是全局的。这个变量存储于模块的一个特殊的可执行部分(一个"ELF段" ),在装载时,内核通过这个段来寻找模块导出的变量(感兴趣的读者可以看<linux/module.h>获知更详细的信息)。

`EXPORT_SYMBOL`和`EXPORT_SYMBOL_GPL`均用于将给定的符号导出到模块外,使这些符号能被其他模块使用。 ### 功能 - `EXPORT_SYMBOL`:允许导出的符号被任何许可证的模块使用。 - `EXPORT_SYMBOL_GPL`:用于导出符号(函数或变量),但只允许GPL许可证的模块来使用这些符号,确保了只有同样是GPL许可证的模块才能使用到这些导出的符号 [^2]。 ### 使用方法 - **符号导出位置**:符号必须在模块文件的全局部分导出,不能在函数中导出,因为这两个将被扩展成一个特殊用途的声明,而该变量必须是全局的。这个变量存储于模块的一个特殊的可执行部分(一个“ELF段”),在装载时,内核通过这个段来寻找模块导出的变量 [^1]。 - **代码示例**: ```c #include <linux/module.h> #include <linux/kernel.h> // 一个简单的内核函数 int my_kernel_function(int arg) { printk("my_kernel_function was called with arg = %d\n", arg); return arg * 2; } // 使用EXPORT_SYMBOL导出符号 EXPORT_SYMBOL(my_kernel_function); // 使用EXPORT_SYMBOL_GPL导出符号 // EXPORT_SYMBOL_GPL(my_kernel_function); MODULE_LICENSE("GPL"); ``` 若使用`EXPORT_SYMBOL_GPL`,还需在模块中使用`MODULE_LICENSE("GPL")`或者`MODULE_LICENSE("Dual BSD/GPL")`,之后才能在模块中引用该符号 [^2][^4]。 ### 区别 - **许可证限制**:`EXPORT_SYMBOL`允许导出的符号被任何许可证的模块使用,而`EXPORT_SYMBOL_GPL`限定了能够调用这个导出符号的其他代码也必须遵守GPL许可证 [^2]。 - **定义**: ```c #define EXPORT_SYMBOL(sym) \ __EXPORT_SYMBOL(sym, "") #define EXPORT_SYMBOL_GPL(sym) \ __EXPORT_SYMBOL(sym, "_gpl") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值