Linux内核模块EXPORT_SYMBOL和EXPORT_SYMBOL_GPL使用说明

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

EXPORT_SYMBOLEXPORT_SYMBOL_GPL 用于导出符号到内核符号表中(内核符号表可通过 ‘/proc/kallsyms’ 查看),导出的符号可以被其它模块调用,调用前需要先声明。

通过 EXPORT_SYMBOL 导出的符号可以被包含GPL许可权的模块和不包含GPL许可权的模块调用;
通过 EXPORT_SYMBOL_GPL 导出的符号只能被包含GPL许可权的模块调用,否则会报错 FATAL: modpost: GPL-incompatible module ***.ko uses GPL-only symbol '***'.

example:模块A导出符号,模块B使用符号,代码如下
A模块代码:

// A module
#include <linux/init.h> 
#include <linux/module.h>

int add_integar(int a, int b)
{
    return a + b;
}
EXPORT_SYMBOL(add_integar);

int sub_integar(int a, int b)
{
    return a - b;
}
EXPORT_SYMBOL_GPL(sub_integar);

static int __init A_init(void)
{
    printk(KERN_INFO "A enter\n");
    return 0;
}

static void __exit A_exit(void) 
{    
  printk(KERN_INFO "A exit\n"); 
}

module_init(A_init);
module_exit(A_exit);

MODULE_AUTHOR("TASK_RUNNING.\n");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("export symbol module.\n");

A模块makefile:

#A module makefile
KVERS = $(shell uname -r)

obj-m += A.o

build: kernel_modules

kernel_modules:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules 

clean:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

A模块编译后,会生成Module.symvers文件,使用 cat Module.symvers可查看内容如下:

0x00000000 sub_integar /home/task_running/test/A/A EXPORT_SYMBOL_GPL
0x00000000 add_integar /home/task_running/test/A/A EXPORT_SYMBOL

当加载A模块时,符号会被导出到内核符号表,使用 grep integar /proc/kallsyms 可查看被导出的符号,使用root权限执行时,可以查看符号对应的地址,普通用户查看的地址为全0

0000000000000000 r __ksymtab_add_integar [A]
0000000000000000 r __kstrtab_add_integar [A]
0000000000000000 r __ksymtab_sub_integar [A]
0000000000000000 r __kstrtab_sub_integar [A]
0000000000000000 T add_integar [A]
0000000000000000 t sub_integar [A]

B模块代码:

// B module
#include <linux/init.h>
#include <linux/module.h>

//此处需要用extern声明外部符号
extern int add_integar(int a, int b);
extern int sub_integar(int a, int b);

static int __init B_init(void)
{
    printk(KERN_INFO "B module enter\n");
    printk(KERN_INFO "ADD = %d\n", add_integar(5, 6));
    printk(KERN_INFO "SUB = %d\n", sub_integar(6, 5));
    return 0;
}

static void __exit B_exit(void)
{
    printk(KERN_INFO "B module exit\n");
}

module_init(B_init);
module_exit(B_exit);

MODULE_AUTHOR("TASK_RUNNING.\n");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("use symbol module.\n");

B模块makefile:

#B module makefile
KVERS = $(shell uname -r)

obj-m += B.o

build:kernel_modules

#此处需要指定A模块编译后生成的Module.symvers文件
KBUILD_EXTRA_SYMBOLS += /home/task_running/test/A/Module.symvers
export KBUILD_EXTRA_SYMBOLS

kernel_modules:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules

clean:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

B模块必须在A模块加载后才能使用A模块的符号,加载B模块后,使用 dmesg 可以查看内核打印的信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、Linux内核模块简介 1.1 Linux内核模块介绍 Linux内核的整体结构已经非常庞大,而其包含的组件也...
    konishi5202阅读 7,974评论 0 4
  • 一、Linux内核简介 1.宏内核与微内核 内核分为四大类:单内核(宏内核);微内核;混合内核;外内核。 宏内核(...
    Mr_Michael阅读 5,822评论 0 2
  • 1 Linux 内核模块简介 Linux 内核是一个十分庞大的系统,如何能够为其瘦身,订制适合自己应用场景的 li...
    守拙圆阅读 4,707评论 0 2
  • 一、什么是内核模块 内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable ...
    JalynFang阅读 3,701评论 0 2
  • 为什么白色这么粗,因为笔贵,舍不得削没有对比就没有伤害,水分都蒸干了,我是不会吃的。
    花芊猪儿阅读 4,929评论 1 4