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

【Linux】内核编程中的EXPORT_SYMBOL()查看符号导出结果命令:以EXPORT_SYMBOL(export_symbol_server)为例:$cat/proc/kallsyms|grepexport_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_,p

大家好,又见面了,我是你们的朋友全栈君。

查看符号导出结果命令:
以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!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160336.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号