【Linux】内核编程中的EXPORT_SYMBOL()

查看符号导出结果命令:
以EXPORT_SYMBOL(export_symbol_server)为例:
$ cat /proc/kallsyms | grep export_symbol_server

一:EXPORT_SYMBOL()宏定义相关定义如下

#define ___PASTE(a, b) a##b
#define __PASTE(a, b) ___PASTE(a, b)

#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)

#define __ADDRESSABLE(sym)                                      \
    static void * __section(".discard.addressable") __used      \
        __UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)&sym;

#define __KSYMTAB_ENTRY(sym, sec)                                \
    __ADDRESSABLE(sym)                                            \
    asm("    .section \"___ksymtab" sec "+" #sym "\", \"a\"    \n"    \
        "    .balign    4                    \n"                        \
        "__ksymtab_" #sym ":                \n"                    \
        "    .long    " #sym "- .                \n"                    \
        "    .long    __kstrtab_" #sym "- .            \n"            \
        "    .long    __kstrtabns_" #sym "- .            \n"            \
        "    .previous                    \n")

#define __CRC_SYMBOL(sym, sec)

#define ___EXPORT_SYMBOL(sym, sec, ns)                                \
    extern typeof(sym) sym;                                            \
    extern const char __kstrtab_##sym[];                            \
    extern const char __kstrtabns_##sym[];                            \
    __CRC_SYMBOL(sym, sec);                                            \
    asm("    .section \"__ksymtab_strings\",\"aMS\",%progbits,1    \n"    \
        "__kstrtab_" #sym ":                    \n"                    \
        "    .asciz     \"" #sym "\"                    \n"                \
        "__kstrtabns_" #sym ":                    \n"                    \
        "    .asciz     \"" ns "\"                    \n"                    \
        "    .previous                        \n");                    \
    __KSYMTAB_ENTRY(sym, sec)

#define __EXPORT_SYMBOL(sym, sec, ns)    ___EXPORT_SYMBOL(sym, sec, ns)
#define _EXPORT_SYMBOL(sym, sec)         __EXPORT_SYMBOL(sym, sec, "")

#define EXPORT_SYMBOL(sym)               _EXPORT_SYMBOL(sym, "")
#define EXPORT_SYMBOL_GPL(sym)           _EXPORT_SYMBOL(sym, "_gpl")
#define EXPORT_SYMBOL_NS(sym, ns)        __EXPORT_SYMBOL(sym, "", #ns)
#define EXPORT_SYMBOL_NS_GPL(sym, ns)    __EXPORT_SYMBOL(sym, "_gpl", #ns)

以EXPORT_SYMBOL(export_symbol_server)宏展开为例:
(1)EXPORT_SYMBOL(export_symbol_server)展开到第二步:
#define EXPORT_SYMBOL(sym)           _EXPORT_SYMBOL(sym, "")
(2)_EXPORT_SYMBOL(export_symbol_server, "")展开到第三步:
#define _EXPORT_SYMBOL(sym, sec)    __EXPORT_SYMBOL(sym, sec, "")
(3)__EXPORT_SYMBOL(export_symbol_server, "", "")
#define __EXPORT_SYMBOL(sym, sec, ns)    ___EXPORT_SYMBOL(sym, sec, ns)
(4)___EXPORT_SYMBOL(export_symbol_server, "", "")展开为具体的符号:
#define ___EXPORT_SYMBOL(sym, sec, ns)
extern typeof(export_symbol_server) export_symbol_server;
extern const char __kstrtab_export_symbol_server[];
extern const char __kstrtabns_export_symbol_server[];
asm("    .section \"__ksymtab_strings\",\"aMS\",%progbits,1    \n"
        "__kstrtab_export_symbol_server:                    \n"    
        "    .asciz     "export_symbol_server"                    \n"
        "__kstrtabns_export_symbol_server:                    \n"    
        "    .asciz                                             \n"
        "    .previous                                        \n");
(5)__KSYMTAB_ENTRY(export_symbol_server, "")展开
__ADDRESSABLE(export_symbol_server)    展开
#define ___PASTE(a, b) a##b
#define __PASTE(a, b) ___PASTE(a, b)
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
static void * __section(".discard.addressable") __used
    __UNIQUE_ID(__addressable_export_symbol_server) = (void *)&export_symbol_server;

__UNIQUE_ID(__addressable_export_symbol_server):
    __UNIQUE_ID___addressable_export_symbol_server__LINE__(行号)
即:static void * __section(".discard.addressable") __used =
    __UNIQUE_ID___addressable_export_symbol_server__LINE__ = (void *)&export_symbol_server;

asm("    .section \"___ksymtab+export_symbol_server\", \"a\"    \n"
        "    .balign    4                                        \n"                       
        "__ksymtab_export_symbol_server:                    \n"                  
        "    .long    export_symbol_server - .                \n"                   
        "    .long    __kstrtab_export_symbol_server- .        \n"           
        "    .long    __kstrtabns_export_symbol_server- .        \n"           
        "    .previous                                        \n")

EXPORT_SYMBOL(export_symbol_server)完全展开:
extern typeof(export_symbol_server) export_symbol_server;
extern const char __kstrtab_export_symbol_server[];
extern const char __kstrtabns_export_symbol_server[];
asm("    .section \"__ksymtab_strings\",\"aMS\",%progbits,1    \n"
        "__kstrtab_export_symbol_server:                    \n"    
        "    .asciz     "export_symbol_server"                    \n"
        "__kstrtabns_export_symbol_server:                    \n"    
        "    .asciz                                             \n"
        "    .previous                                        \n");
static void * __section(".discard.addressable") __used =
    __UNIQUE_ID___addressable_export_symbol_server__LINE__ = (void *)&export_symbol_server;        
asm("    .section \"___ksymtab+export_symbol_server\", \"a\"    \n"
        "    .balign    4                                        \n"                       
        "__ksymtab_export_symbol_server:                    \n"                  
        "    .long    export_symbol_server - .                \n"                   
        "    .long    __kstrtab_export_symbol_server- .        \n"           
        "    .long    __kstrtabns_export_symbol_server- .        \n"           
        "    .previous                                        \n")

符号导出结果查询:
$ cat /proc/kallsyms | grep export_symbol_server
0000000000000000 r __kstrtab_export_symbol_server    [export_symbol_server]
0000000000000000 r __kstrtabns_export_symbol_server    [export_symbol_server]
0000000000000000 r __ksymtab_export_symbol_server    [export_symbol_server]
0000000000000000 T export_symbol_server    [export_symbol_server]
0000000000000000 r __func__.20199    [export_symbol_server]
0000000000000000 t export_symbol_exit    [export_symbol_server]
0000000000000000 r _note_9    [export_symbol_server]
0000000000000000 r _note_8    [export_symbol_server]
0000000000000000 d __this_module    [export_symbol_server]
0000000000000000 t cleanup_module    [export_symbol_server]

二:EXPORT_SYMBOL的作用

EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。
导出符号不调用,改函数所做的动作也不会被执行。

三:使用方法

1、在模块函数定义之后使用"EXPORT_SYMBOL(函数名)"来声明。
2、在调用该函数的另外一个模块中使用extern对之声明。
3、先加载定义该函数的模块,然后再加载调用该函数的模块,请注意这个先后顺序。
注意:需要添加许可证:MODULE_LICENSE("GPL v2"), 不然编译报错

四:测试程序

// export_symbol_server.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>


static int export_symbol_server(void)
{
    printk("EXPORT_SYMBOL In Server: %s...\n",__func__);
    return 0;
}
EXPORT_SYMBOL(export_symbol_server);

static int __init export_symbol_init(void)
{
    printk("EXPORT_SYMBOL Module Server Init!\n");
    return 0;
}

static void __exit export_symbol_exit(void)
{
    printk("EXPORT_SYMBOL Module Server Exit!\n");
}

MODULE_LICENSE("GPL v2");
module_init(export_symbol_init);
module_exit(export_symbol_exit);
// export_symbol_client.c
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>

static int call_export_symbol(void)
{
    extern int export_symbol_server(void);
    printk("EXPORT_SYMBOL In Client: %s...\n",__func__);
    export_symbol_server();
    return 0;
}

static int __init export_symbol_init(void)
{
    printk("EXPORT_SYMBOL Module Client Init!\n");
    call_export_symbol();
    return 0;
}

static void __exit export_symbol_exit(void)
{
    printk("EXPORT_SYMBOL Module Client Exit!\n");
}

MODULE_LICENSE("GPL v2");
module_init(export_symbol_init);
module_exit(export_symbol_exit);
// Makefile
obj-m += export_symbol_server.o
obj-m += export_symbol_client.o

KDIR := /home/myroot/linux/linux-5.15.7 #内核源码路径
PWD ?= $(shell pwd)

all:
    make -C $(KDIR) M=$(PWD) modules
 
clean:
    rm -rf *.o *.mod* *.order *.symvers *.ko

五:加载内核模块

$ sudo insmod export_symbol_server.ko
$ sudo insmod export_symbol_client.ko

安装完内核模块后,查看符号导出情况:以EXPORT_SYMBOL(export_symbol_server)为例:
$ cat /proc/kallsyms | grep export_symbol_server
0000000000000000 r __kstrtab_export_symbol_server    [export_symbol_server]
0000000000000000 r __kstrtabns_export_symbol_server    [export_symbol_server]
0000000000000000 r __ksymtab_export_symbol_server    [export_symbol_server]
0000000000000000 T export_symbol_server    [export_symbol_server]
0000000000000000 r __func__.20199    [export_symbol_server]
0000000000000000 t export_symbol_exit    [export_symbol_server]
0000000000000000 r _note_9    [export_symbol_server]
0000000000000000 r _note_8    [export_symbol_server]
0000000000000000 d __this_module    [export_symbol_server]
0000000000000000 t cleanup_module    [export_symbol_server]

查看内核模块加载情况:
$  dmesg | tail -5
[ 4777.098112] EXPORT_SYMBOL Module Server Init!
[ 4788.859055] EXPORT_SYMBOL Module Client Init!
[ 4788.859058] EXPORT_SYMBOL In Client: call_export_symbol...
[ 4788.859059] EXPORT_SYMBOL In Server: export_symbol_server...
卸载内核模块:注意顺序,先卸载调用导出函数符号的模块, 在卸载导出符号模块
$ sudo rmmod export_symbol_client
$ sudo rmmod export_symbol_server
$ dmesg | tail -3
[ 4969.121642] EXPORT_SYMBOL Module Client Exit!
[ 4976.353065] EXPORT_SYMBOL Module Server Exit!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值