linux 导出符号与函数引用

前言

EXPORT_SYMBOL 宏的使用时出现在 Linux 2.6 版本之后,在 Linux 2.4 内核中,默认的非 static 函数和变量都会自动导入到内核空间,不需要用 EXPORT_SYMBOL() 做标记的。出于安全考虑,不久之后 Linux 2.6 修改为默认不导出所有的符号,需要导出的符号使用 EXPORT_SYMBOL() 进行标记。


一、EXPORT_SYMBOL 宏的作用

EXPORT_SYMBOL 标签内指定的符号(函数或变量)对全部内核代码公开,不用修改内核代码就可以在内核模块中直接调用,即使用 EXPORT_SYMBOL 可以将一个函数以符号的方式导出给其他模块使用。简单来说,EXPORT_SYMBOL 的作用就是导出符号到内核符号表以供其他模块使用。

符号的意思就是函数的入口地址,或者说是把这些符号和对应的地址保存起来的,在内核运行的过程中,可以找到这些符号对应的地址的。

EXPORT_SYMBOL_GPL 宏

除了使用 EXPORT_SYMBOL 宏,Linux 内核还提供了 EXPORT_SYMBOL_GPL 宏,它们的作用都是将符号导出到内核符号表。区别在于 EXPORT_SYMBOL_GPL 仅将符号导出到 GPL 许可的模块。

EXPORT_SYMBOL exports the symbol to any loadable module.
EXPORT_SYMBOL_GPL exports the symbol only to GPL-licensed modules.

二、EXPORT_SYMBOL 使用方法

  1. 在模块函数定义之后使用 EXPORT_SYMBOL(函数名)
  2. 在调用该函数的模块中使用 extern 对要使用的符号或者函数进行声明
  3. 首先加载定义该函数的模块,再加载调用该函数的模块
使用范例

在这里插入图片描述
可以看到,mg_cpld 定义了接口函数 common_lpc_to_cpld_get(),并且使用 EXPORT_SYMBOL_GPL 导出该函数。psu 模块使用 extern 表示 common_lpc_to_cpld_get() 已在其他模块中定义。

root@local:/home/admin# 
root@local:/home/admin# insmod mg_cpld.ko 
root@local:/home/admin# insmod cpld_psu_ym2651y.ko 
root@local:/home/admin# dmesg -c
[  569.496376] psu_mod_init success!

可以看到,先加载定义了 common_lpc_to_cpld_get() 函数的 mg_cpld.ko,接着加载引用了 common_lpc_to_cpld_get() 函数的 cpld_psu_ym2651y.ko,正常。

root@local:/home/admin# rmmod mg_cpld.ko 
root@local:/home/admin# rmmod cpld_psu_ym2651y.ko 
root@local:/home/admin# dmesg -c
[  694.830738] psu_mod_exit success!
root@local:/home/admin# 
root@local:/home/admin# insmod cpld_psu_ym2651y.ko
insmod: ERROR: could not insert module cpld_psu_ym2651y.ko: Unknown symbol in module
root@local:/home/admin# dmesg -c
[  725.700745] cpld_psu_ym2651y: Unknown symbol common_lpc_to_cpld_get (err 0)
root@local:/home/admin# 

可以看到,如果我们先加载引用了 common_lpc_to_cpld_get() 函数的 cpld_psu_ym2651y.ko,而不是先加载定义了 common_lpc_to_cpld_get() 函数的 mg_cpld.ko,就会有依赖错误:找不到 common_lpc_to_cpld_get() 标识符。

注意:如果 export 导出的函数是静态函数,编译时可能会产生警告甚至报错。

在这里插入图片描述


三、EXPORT_SYMBOL 的另一种补充

EXPORT_SYMBOL 会导致 linux 驱动出现模块依赖的问题。

如果多个驱动模块都是调用同一个 公共接口代码的库(common code),我们也可以把所有的公共接口代码单独存放一个文件,然后把该文件编译进驱动模块中。

示例如下:

公共代码库:
在这里插入图片描述
在这里插入图片描述

Makefile:将公共代码与驱动源文件一起编译成一个 .ko 驱动模块

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值