【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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java向上取整和向下取整,万字长文!

    java向上取整和向下取整,万字长文!一面:70分钟突击电话面试正思考着项目功能模块,阿里面试官打来了电话,开始了阿里一面。阿里面试官自我介绍,介绍了5分钟左右,部门的情况,主要的业务提问开始会哪些操作系统Linux会一点说一下操作指令,怎么看cpu,看进程,看端口操作系统进程间通信追问了一个信号相关的问题,我不知道了。io多路复用,说一说面向切面编程,说一说那些场景说说面向切面编程给一个场景,有很多方法,找出耗时长的方法spring的@autowired的作用mybatis和hibernate的区别C,C

    2022年6月21日
    28
  • knn算法实现手写数字识别的背景_knn手写数字识别60000训练集

    knn算法实现手写数字识别的背景_knn手写数字识别60000训练集KNN最邻近分类算法:(近邻取样)邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是机器学习分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。属于监督学习,有类别标记,且KNN是惰性学习。叫做Memory-basedlearning、也叫instance-basedlearning.他…

    2022年9月14日
    0
  • Informix 常用函数

    Informix 常用函数一、内部函数1、内部合计函数1)COUNT(*)返回行数2)COUNT(DISTINCTCOLNAME)返回指定列中唯一值的个数3)SUM(COLNAME/EXPRESSION)返回指

    2022年7月3日
    23
  • 博客营销BlogUp

    博客营销BlogUp九丁博客群发工具BlogUp是一款强大的博客营销工具,具有博客全自动群发、博客帐号辅助群建、帐号分组管理、博客文章可视化管理、文章伪原创、超链接自动插入、文章自动采集、关键词设置、标签设置、自动更换IP等核心功能。是商家、站长、写手、个人、公司等用于网络营销、软文推广、博客写作、网络推广、SEO的绝佳工具。利用BlogUp可以帮您增加搜索引擎信息收录量,提高搜索引擎排名,快速提高产品、网站、文章等…

    2022年7月14日
    17
  • 极光漏洞,”极光”ie漏洞,微软发布2010年第一个IE 0day漏洞“极光”警告、最新官方补丁和解决办法

    极光漏洞,”极光”ie漏洞,微软发布2010年第一个IE 0day漏洞“极光”警告、最新官方补丁和解决办法微软2010年1月14日晚发布公告称,黑客在最近的针对Google、Adobe以及其他公司的攻击中利用了IE零日漏洞。远程代码执行漏洞影响到各Windows版本上运行的近乎全部的IE版本。关键字:极光

    2022年7月2日
    21
  • 离散数学:判断任意一个关系是否为函数,若是函数,判定其是否为单射、满射或双射[通俗易懂]

    离散数学:判断任意一个关系是否为函数,若是函数,判定其是否为单射、满射或双射[通俗易懂]题目:函数的判定内容:判断任意一个关系是否为函数,若是函数,判定其是否为单射、满射或双射。要求:1、提供函数(f:A—>B)的输入接口;(输入包括集合A,集合B和具体的函数关系(序偶集));2、对函数的性质进行判断(判断单射、满射和双射);3、提供判断结果的输出。代码:#include<string.h>#include<iostream>usingnamespacestd;char*A,*B,*F;inta,b,f;intJudge(c

    2022年5月31日
    69

发表回复

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

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