【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!

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

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

(1)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 新游戏世界合集全文_经典种田文完结推荐

    新游戏世界合集全文_经典种田文完结推荐送给所有爱玩游戏的老鸟们 老游戏中有大量经典作品,其中中文的HGAME更是经典中的经典! ◆告别的年代失色的回忆?——新系统下经典老游戏重玩全攻略◆  “新”与“老”当然是相对的,不过在开篇之前有必要确定我们的讨论范畴,这里的“老”是指为Win98之前的操作系统,包括DOS和Win32/95,而新系统则是指Win98/2000/XP。毫无疑问,有很多老游戏都很值得我们来重温,但重

    2022年9月21日
    0
  • 中文人物关系图谱构建与应用项目(人物关系抽取,关系抽取评测)

    中文人物关系图谱构建与应用项目(人物关系抽取,关系抽取评测)ChinesePersonRelationGraphChinesePersonRelationGraph,personrelationshipextractionbasedonnlpmethods.中文人物关系知识图谱项目,内容包括中文人物关系图谱构建,基于知识库的数据回标,基于远程监督与bootstrapping方法的人物关系抽取,基于知识图谱的知识问答等应用.项目地址:htt…

    2022年6月26日
    47
  • GFS – The Google File System

    GFS – The Google File SystemTheGoogleFileSystemhttp://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.125.789&amp;rep=rep1&amp;type=pdfhttp://www.dbthink.com/?p=501,中文翻译 Google牛人云集的地方,但在设计系统时,却非常务实,没有采用什么复杂和时髦…

    2022年6月1日
    48
  • webstorm插件开发

    webstorm插件开发前言最近有开发webstrom插件的需求,可是百度一下发现网上关于webstorm插件开发的文章实在是寥寥无几,本文记录一下本次插件开发走的路和踩的坑。希望对后来的同学能有些许的帮助。正文准备工作intelliJ平台的所有插件开发都是基于java语言,所以在进入开发工作之前必须对java语言有一定的了解,本人作为java门外汉,花…

    2022年9月8日
    0
  • Welcome to Xiao

    Welcome to Xiao这里写自定义目录标题WelcometoXiao新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML图表FLowchart流程图导出与导入导出导入WelcometoXiao你好!这是你第一次使用Markdown编辑器所展示的欢迎页。如果你想学习如何使用Mar

    2022年10月7日
    0
  • java编程代码都是背下来的吗_向学弟学妹们介绍自己的大学

    java编程代码都是背下来的吗_向学弟学妹们介绍自己的大学同学们好,今天二哥是来还债的,记得先拖到文末点个赞再回来细细的读,好不好!最近一段时间,我一直在学习Java虚拟机和字节码方面的知识,为的就是有朝一日成为真正牛逼的技术大佬!不知道大家有没有这种感觉,就是一开始学习编程的时候,真心不想看底层的东西,就想直接上来撸代码,但时间久了以后,总感觉缺点啥~~~~于是我开始阅读《深入理解计算机系统》、《图解TCP/IP》、《深入理解Java虚拟机》这些偏底层的书籍,看得烦了,就去刷我之前给大家推荐过的两个视频课,《哈佛大学的CS50》和《计算机科学速成

    2022年10月30日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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