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

https://www.jianshu.com/p/fd89d4d69772

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

EXPORT_SYMBOL 和 EXPORT_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 可以查看内核打印的信息。

猜你喜欢

转载自blog.csdn.net/qq_41483419/article/details/130821062