打印

LINUX EXPORT_SYMBOL_GPL及EXPORT_SYMBOL导出函数

[复制链接]
119|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
车水马龙|  楼主 | 2018-9-28 12:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1 )、EXPORT_SYMBOL(),这个宏也是将函数导出让所有模块都可以使用,而EXPORT_SYMBOL_GPL()这个宏主要是给有GPL认证的模块使用。

2)、EXPORT_SYMBOL标签内定义的函数对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用。

3)、EXPORT_SYMBOL(符号名);  EXPORT_SYMBOL_GPL(符号名)  





一)主要作之一: 内核"导出"的符号表,这个表在insmod 时候会用到.

1./proc/kallsyms

cat /proc/kallsyms会打印出内核当前的符号表,例如:

...

d8834a24 t snd_free_sgbuf_pages [snd_page_alloc]

d8834ab5 t snd_malloc_sgbuf_pages [snd_page_alloc]

c014f906 U kmem_cache_alloc [snd_page_alloc]

c0106dcd U dma_alloc_coherent [snd_page_alloc]

...

其中第一列是该符号在内核地址空间中的地址;第二列是符号属性,小写表示

局部符号,大写表示全局符号,具体含义参考man nm; 第三列表示符号字符串.

这里只能显示EXPORT_SYMBOL,EXPROT_SYMBOL_GPL处理过的符号。

2.System.map内核符号文件

通过more /boot/System.map 可以查看内核符号列表。

可以显示编译好内核后所有在内核中的符号,模块中的要另行查看。

3.通过nm vmlinux也可以查看内核符号列表

可以显示编译好内核后所有在内核中的符号,模块中的要另行查看。

4.通过nm module_name可以查看模块的符号列表

但是得到是相对地址,只有加载后才会分配绝对地址。比如:e1000模块,如果e1000中的符号经过EXPORT_SYMBOL处理,

等加载后,我们可以通过more /boot/System.map和nm vmlinux命令查看到,但是没有EXPORT_SYMBOL的,不能查看。

代码如:

int __gpio_cansleep(unsigned gpio)

{

struct gpio_chip *chip; /* only call this on GPIOs that are valid! */

chip = gpio_to_chip(gpio);

return chip->can_sleep;

}

EXPORT_SYMBOL_GPL(__gpio_cansleep);

/**

* __gpio_to_irq() - return the IRQ corresponding to a GPIO

* @gpio: gpio whose IRQ will be returned (already requested)

* Context: any

*

* This is used directly or indirectly to implement gpio_to_irq().

* It returns the number of the IRQ signaled by this (input) GPIO,

* or a negative errno.

*/

int __gpio_to_irq(unsigned gpio)

{

struct gpio_chip *chip;

chip = gpio_to_chip(gpio);

return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;

}

EXPORT_SYMBOL_GPL(__gpio_to_irq);



二) EXPORT_SYMBOL_GPL导出函数





        如果要用EXPORT_SYMBOL_GPL导出函数,使用此函数的模块需要MODULE_LICENSE("GPL") 或MODULE_LICENSE("Dual  BSD/GPL")之后才能在模块中引用来声明



三)EXPORT_SYMBOL 导出函数



include/module.h:



struct kernel_symbol

{

    unsigned long value;   

    const char *name;

};

/* For every exported symbol, place a struct in the __ksymtab section */

#define __EXPORT_SYMBOL(sym, sec)               \

    __CRC_SYMBOL(sym, sec)                  \

    static const char __kstrtab_##sym[]         \

    __attribute__((section("__ksymtab_strings")))       \

    = MODULE_SYMBOL_PREFIX #sym;                        \

    static const struct kernel_symbol __ksymtab_##sym   \

    __attribute_used__                  \

    __attribute__((section("__ksymtab" sec), unused))   \

    = { (unsigned long)&sym, __kstrtab_##sym }

#define EXPORT_SYMBOL(sym)                  \

    __EXPORT_SYMBOL(sym, "")

#define EXPORT_SYMBOL_GPL(sym)                  \

    __EXPORT_SYMBOL(sym, "_gpl")

#endif



Analysis:



1. kernel_symbol: 内核函数符号结构体

value: 记录使用EXPORT_SYMBOL(fun),函数fun的地址

name: 记录函数名称("fun"),在静态内存中



2. EXPORT_SYMBOL(sym) :导出函数符号,保存函数地址和名称



宏等价于:(去掉gcc的一些附加属性,MODULE_SYMBOL_PREFIX该宏一般是"")



static const char __kstrtab_sym[] = "sym";

static const struct kernel_symbol __ksymtab_sym =

    {(unsigned long)&sym, __kstrtab_sym }





3. gcc 附加属性

1>. __atrribute__ 指定变量或者函数属性。

__attribute((section("section-name")) var : 编译器将变量var放在section-name所指定的data或者bss段里面。



很容易看出:EXPORT_SYMBOL(sym)将sym函数的名称__kstrtab_sym记录在,段名为"__kstrtab_strings"数据段中。 将sym所对应的kernel_symbol记录在名为__ksymtab段中。

EXPORT_SYMBOL_GPL(sym) 和EXPORT_SYMBOL不同之处在于sym对应的kenel_symbol记录在__ksymtab_gpl段中。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

474

主题

476

帖子

0

粉丝