Jee*_*tel 38 c linux linux-kernel
从这里开始
48 struct snd_card *snd_cards[SNDRV_CARDS];
49 EXPORT_SYMBOL(snd_cards);
Run Code Online (Sandbox Code Playgroud)
我不知道它的含义以及为什么使用它.我试图搜索它,但没有理解它的含义.
这是一个很好的解释。
https://www.quora.com/What-is-the-difference-between-extern-and-EXPORT_SYMBOL-in-Linux-kernel-codes
Extern 是 C 存储类关键字。在内核中,就像在任何其他 C 代码中一样,它告诉编译器它所限定的变量或函数的定义是在另一个“文件”中实现的,或者更准确地说,是翻译单元(编程)——维基百科。定义它的翻译单元不应使用静态限定符。因此,符号表有一个与之对应的条目。在链接时,符号会正常解析。没有任何关于“extern”的内核特定内容。
EXPORT_SYMBOL() 是 Linux 内核头文件定义的宏。它与 extern 没有太多共同之处。它告诉 kbuild 机制所引用的符号应该是内核符号全局列表的一部分。这反过来又允许内核模块访问它们。内核本身(而不是模块)中的代码当然可以根据常规 C 通过 extern 声明访问任何非静态符号。 EXPORT_SYMBOL() 机制允许我们导出一个符号以供使用也通过可加载模块。有趣的是,一个模块导出的符号可以被另一个依赖它的模块访问!
总而言之, extern 不是特定于内核的。它用于将声明限定为来自另一个翻译单元的非静态符号。EXPORT_SYMBOL() 特定于 Linux 内核。它在定义的翻译单元中使用以使符号可用于可加载模块。
所以 EXPORT_SYMBOL 只是一种类似于 extern 的机制,但它是用于可加载模块之间的参考,而不是文件。
往前走,我们可以猜测它是由 extern 实现的,因为 extern 是形式 C,这是基础。
这是一个线索。
https://elixir.bootlin.com/linux/v4.6.7/source/include/linux/export.h#L56
#define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "")
/* For every exported symbol, place a struct in the __ksymtab section */
#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 }
Run Code Online (Sandbox Code Playgroud)
首先声明一个extern sym。
然后是一个字符串 __kstrtab_##sym == VMLINUX_SYMBOL_STR(sym)。
最后一个 extern struct kernel_symbol __ksymtab_##sym = { (unsigned long) &sym , __kstrtab_##sym }。 &sym记录函数或变量等sym的真实地址,_ kstrtab ##sym记录名称字符串。
正如我的评论所承诺的那样,它本身不是答案,而是演示,并不需要导出的符号是非静态的。以下2个模块演示了这一点:
/* mod1.c */
#include <linux/module.h>
static int mod1_exp_func(int i)
{
pr_info("%s:%d the value passed in is %d\n",
__func__, __LINE__, i);
return i;
}
EXPORT_SYMBOL(mod1_exp_func); /* export static symbol */
static int __init mod1_init(void)
{
pr_info("Initializing simple mod\n");
return 0;
}
static void __exit mod1_exit(void)
{
pr_info("This module is exiting\n");
}
module_init(mod1_init);
module_exit(mod1_exit);
MODULE_LICENSE("GPL v2");
Run Code Online (Sandbox Code Playgroud)
第二个模块
/* mod2.c */
#include <linux/module.h>
extern int mod1_exp_func(int);
static int __init mod2_init(void)
{
pr_info("Initializing mod2\n");
pr_info("Calling exported function in mod1\n");
mod1_exp_func(3);
return 0;
}
static void __exit mod2_exit(void)
{
pr_info("mod2 exiting\n");
}
module_init(mod2_init);
module_exit(mod2_exit);
MODULE_LICENSE("GPL v2");
Run Code Online (Sandbox Code Playgroud)
这些分别在CentOS 6和CentOS 7:内核2.6.32和3.10上进行了测试。加载mod1.ko然后再加载mod2.ko将导致传递给mod1_exp_func()的值被打印到内核日志缓冲区。
归档时间: |
|
查看次数: |
45342 次 |
最近记录: |