亚洲综合图片区自拍_思思91精品国产综合在线观看_一区二区三区欧美_欧美黑人又粗又大_亚洲人成精品久久久久桥本

Linux內(nèi)核模塊間通訊方法 全球快看

2023-06-07 16:12:38 來(lái)源:Linux二進(jìn)制

Linux內(nèi)核模塊間通訊方法非常的多,最便捷的方法莫過(guò)于函數(shù)或變量符號(hào)導(dǎo)出,然后直接調(diào)用。默認(rèn)情況下,模塊與模塊之間、模塊與內(nèi)核之間的全局變量是相互獨(dú)立的,只有通過(guò)EXPORT_SYMBOL將模塊導(dǎo)出才能對(duì)其他模塊或內(nèi)核可見(jiàn)。

符號(hào)導(dǎo)出函數(shù)


(資料圖片僅供參考)

EXPORT_SYMBOL():括號(hào)中定義的函數(shù)或變量對(duì)全部?jī)?nèi)核代碼公開(kāi)EXPORT_SYMBOL_GPL()EXPORT_SYMBOL類(lèi)似,但范圍只適合GPL許可的模塊進(jìn)行調(diào)用

一、內(nèi)核符號(hào)表

Linux kallsyms,即內(nèi)核符號(hào)表,其中會(huì)列出所有的Linux內(nèi)核中的導(dǎo)出符號(hào),在用戶(hù)態(tài)下可以通過(guò)/proc/kallsyms訪(fǎng)問(wèn),此時(shí)由于內(nèi)核保護(hù),看到的地址為0x0000000000000000,在root模式下可以看到真實(shí)地址。啟用kallsyms需要編譯內(nèi)核時(shí)設(shè)置CONFIG_KALLSYMS為y。

/proc/kallsyms會(huì)顯示內(nèi)核中所有的符號(hào),但是這些符號(hào)不是都能被其他模塊引用的(絕大多數(shù)都不能),能被引用的符號(hào)是被EXPORT_SYMBOLEXPORT_SYMBOL_GPL導(dǎo)出的

內(nèi)核模塊在編譯時(shí)符號(hào)的查找順序:

在本模塊中符號(hào)表中,尋找符號(hào)(函數(shù)或變量實(shí)現(xiàn))在內(nèi)核全局符號(hào)表中尋找在模塊目錄下的Module.symvers文件中尋找

內(nèi)核符號(hào)表類(lèi)型

內(nèi)核符號(hào)表就是在內(nèi)核內(nèi)部函數(shù)或變量中可供外部引用的函數(shù)和變量的符號(hào)表(/proc/kallsyms),表格如下:

符號(hào)類(lèi)型名稱(chēng)說(shuō)明
AAbsolute符號(hào)的值是絕對(duì)值,并且在進(jìn)一步鏈接過(guò)程中不會(huì)被改變
BBSS符號(hào)在未初始化數(shù)據(jù)區(qū)或區(qū)(section)中,即在BSS段中
CCommon符號(hào)是公共的。公共符號(hào)是未初始化的數(shù)據(jù)。在鏈接時(shí),多個(gè)公共符號(hào)可能具有同一名稱(chēng)。如果該符號(hào)定義在其他地方,則公共符號(hào)被看作是未定義的引用
DData符號(hào)在已初始化數(shù)據(jù)區(qū)中
GGlobal符號(hào)是在小對(duì)象已初始化數(shù)據(jù)區(qū)中的符號(hào)。某些目標(biāo)文件的格式允許對(duì)小數(shù)據(jù)對(duì)象(例如一個(gè)全局整型變量)可進(jìn)行更有效的訪(fǎng)問(wèn)
IInderect符號(hào)是對(duì)另一個(gè)符號(hào)的間接引用
NDebugging符號(hào)是一個(gè)調(diào)試符號(hào)
RReadonly符號(hào)在一個(gè)只讀數(shù)據(jù)區(qū)中
SSmall符號(hào)是小對(duì)象未初始化數(shù)據(jù)區(qū)中的符號(hào)
TText符號(hào)是代碼區(qū)中的符號(hào)
UUndefined符號(hào)是外部的,并且其值為0(未定義)
VWeaksymbol弱符號(hào)
WWeaksymbol弱符號(hào)
-Stabs符號(hào)是a.out目標(biāo)文件中的一個(gè)stab符號(hào),用于保存調(diào)試信息
?Unknown符號(hào)的類(lèi)型未知,或者與具體文件格式有關(guān)

:符號(hào)屬性,小寫(xiě)表示局部符號(hào),大寫(xiě)表示全局符號(hào)

二、Linux內(nèi)核符號(hào)導(dǎo)出

1、EXPORT_SYMBOL導(dǎo)出符號(hào)

這里我們定義兩個(gè)源文件myexportfunc.cmyusefunc.c,分別放置在不同目錄;在myexportfunc.c文件中導(dǎo)出publicFunc函數(shù)和變量myOwnVar以供myusefunc.c文件中的函數(shù)調(diào)用。myusefunc.c文件中要想成功調(diào)用publicFunc函數(shù)和myOwnVar變量,必須進(jìn)行extern聲明,否則編譯時(shí)會(huì)報(bào)錯(cuò)。源碼如下:

myexportfunc.c文件:

/* myexportfunc.c */#include < linux/module.h >#include < linux/kernel.h >#include < linux/init.h >char myOwnVar[30]="Linux kernel communication.";static int __init myfunc_init(void){    printk("Hello,this is my own module!\\n");    return 0;}static void __exit myfunc_exit(void){    printk("Goodbye,this is my own clean module!\\n");}void publicFunc(void){    printk(KERN_INFO "This is public module and used for another modules.\\n");}module_init(myfunc_init);module_exit(myfunc_exit);EXPORT_SYMBOL(publicFunc);EXPORT_SYMBOL(myOwnVar);MODULE_DESCRIPTION("First Personel Module");MODULE_AUTHOR("Lebron James");MODULE_LICENSE("GPL");

myexportfunc.c文件的Makefile文件:

ifneq ($(KERNELRELEASE),)$(info "2nd")obj-m:=myexportfunc.oelseKDIR :=/lib/modules/$(shell uname -r)/buildPWD  :=$(shell pwd)all:        $(info "1st")        make -C $(KDIR) M=$(PWD) modulesclean:        rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order *.modendif

myusefunc.c文件:

/* myusefunc.c */#include < linux/init.h >#include < linux/module.h >MODULE_LICENSE("GPL");extern void publicFunc(void);extern char myOwnVar[30];void showVar(void);static int __init hello_init(void){        printk(KERN_INFO "Hello,this is myusefunc module.\\n");        publicFunc();        showVar();        return 0;}static void __exit hello_exit(void){        printk(KERN_INFO "Goodbye this is myusefunc module.\\n");}void showVar(void){        printk(KERN_INFO "%s\\n", myOwnVar);}module_init(hello_init);module_exit(hello_exit);

myusefunc.c文件的Makefile文件:

KBUILD_EXTRA_SYMBOLS += /tmp/tmp/Module.symversifneq ($(KERNELRELEASE),)$(info "2nd")obj-m:=myusefunc.oelseKDIR :=/lib/modules/$(shell uname -r)/buildPWD  :=$(shell pwd)all:        $(info "1st")        make -C $(KDIR) M=$(PWD) modulesclean:        rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order *.modendif

注:KBUILD_EXTRA_SYMBOLS用來(lái)告訴內(nèi)核當(dāng)前module需要引用另外一個(gè)module導(dǎo)出的符號(hào)。KBUILD_EXTRA_SYMBOLS后需要寫(xiě)絕對(duì)路徑,相對(duì)路徑會(huì)出錯(cuò),因?yàn)?code>scripts/mod/modpost執(zhí)行時(shí), 以其在內(nèi)核目錄的路徑為起始點(diǎn)進(jìn)行解析。

分別通過(guò)make命令編譯myexportfunc.cmyusefunc.c文件:

[root@localhost tmp]# make"1st"make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp modulesmake[1]: Entering directory "/usr/src/kernels/4.18.0-394.el8.x86_64""2nd"  CC [M]  /tmp/tmp/myexportfunc.o  Building modules, stage 2."2nd"  MODPOST 1 modules  CC      /tmp/tmp/myexportfunc.mod.o  LD [M]  /tmp/tmp/myexportfunc.komake[1]: Leaving directory "/usr/src/kernels/4.18.0-394.el8.x86_64"[root@localhost tmp]# ls -ltotal 488drwxr-xr-x 3 root root    139 May 25 04:40 24-rw-r--r-- 1 root root    260 May 24 13:34 Makefile-rw-r--r-- 1 root root     32 May 25 04:40 modules.order-rw-r--r-- 1 root root    114 May 25 04:40 Module.symvers-rw-r--r-- 1 root root    655 May 25 04:40 myexportfunc.c-rw-r--r-- 1 root root 237256 May 25 04:40 myexportfunc.ko-rw-r--r-- 1 root root    826 May 25 04:40 myexportfunc.mod.c-rw-r--r-- 1 root root 117856 May 25 04:40 myexportfunc.mod.o-rw-r--r-- 1 root root 121336 May 25 04:40 myexportfunc.o[root@localhost tmp]# cd 24/[root@localhost 24]# lsMakefile  myusefunc.c[root@localhost 24]# make"1st"make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp/24 modulesmake[1]: Entering directory "/usr/src/kernels/4.18.0-394.el8.x86_64""2nd"  CC [M]  /tmp/tmp/24/myusefunc.o  Building modules, stage 2."2nd"  MODPOST 1 modules  CC      /tmp/tmp/24/myusefunc.mod.o  LD [M]  /tmp/tmp/24/myusefunc.komake[1]: Leaving directory "/usr/src/kernels/4.18.0-394.el8.x86_64"[root@localhost tmp]# cd ..[root@localhost tmp]# insmod ./myexportfunc.ko[root@localhost tmp]# cd 24/[root@localhost 24]# ls -ltotal 488-rw-r--r-- 1 root root    305 May 24 13:34 Makefile-rw-r--r-- 1 root root     32 May 25 04:42 modules.order-rw-r--r-- 1 root root    114 May 25 04:42 Module.symvers-rw-r--r-- 1 root root    557 May 24 13:33 myusefunc.c-rw-r--r-- 1 root root 235832 May 25 04:42 myusefunc.ko-rw-r--r-- 1 root root    898 May 25 04:42 myusefunc.mod.c-rw-r--r-- 1 root root 117984 May 25 04:42 myusefunc.mod.o-rw-r--r-- 1 root root 119392 May 25 04:42 myusefunc.o[root@localhost 24]# insmod ./myusefunc.ko[root@localhost 24]#[root@localhost 24]# lsmod | grep -E "myexportfunc|myusefunc"myusefunc              16384  0myexportfunc           16384  1 myusefunc

注:這里必須先insmod myexportfunc模塊,再insmod myusefunc模塊。假如先insmod myusefunc模塊,則會(huì)發(fā)生如下錯(cuò)誤:

[root@localhost 24]# insmod ./myusefunc.koinsmod: ERROR: could not insert module ./myusefunc.ko: Unknown symbol in module[root@localhost 24]# lsmod | grep myusefunc[root@localhost 24]#

且通過(guò)lsmod查看可知,模塊未能加載成功。

Linux內(nèi)核知道的所有符號(hào)都列在/proc/kallsyms中。讓我們?cè)谶@個(gè)文件中搜索我們的符號(hào)。

[root@localhost 24]# cat /proc/kallsyms | grep -E "publicFunc|myOwnVar"ffffffffc0480030 r __ksymtab_myOwnVar   [myexportfunc]ffffffffc04800e4 r __kstrtab_myOwnVar   [myexportfunc]ffffffffc0480040 r __ksymtab_publicFunc [myexportfunc]ffffffffc04800ed r __kstrtab_publicFunc [myexportfunc]ffffffffc047f000 T publicFunc   [myexportfunc]ffffffffc0481000 D myOwnVar     [myexportfunc]

我們可以看到,我們導(dǎo)出的符號(hào)列在內(nèi)核識(shí)別的符號(hào)中。上述列表信息具體含義解釋?zhuān)?/p>

第一列,是該符號(hào)在內(nèi)核地址空間中的地址

第二列,是符號(hào)屬性,小寫(xiě)表示局部符號(hào),大寫(xiě)表示全局符號(hào)(具體含義參考man nm)

第三列,表示符號(hào)字符串(即函數(shù)名或變量等)

第四列,表示加載的驅(qū)動(dòng)名稱(chēng)

如果您查看編譯模塊所在目錄中的Module.symvers文件,將看到一行類(lèi)似于以下內(nèi)容

[root@localhost tmp]# cat Module.symvers0x4db1caee      publicFunc      /tmp/tmp/myexportfunc   EXPORT_SYMBOL0x519e6cfa      myOwnVar        /tmp/tmp/myexportfunc   EXPORT_SYMBOL

Module.symvers包含所有導(dǎo)出的列表符號(hào),Module.symversfile 的語(yǔ)法格式: ;當(dāng)內(nèi)核編譯選項(xiàng)CONFIG_MODVERSIONS關(guān)閉時(shí),所有的CRC值都為0x00000000

上述編譯并且加載模塊完畢后, 通過(guò)dmesg可以看到打印信息如下:

[root@localhost 24]# dmesg[1028204.777932] Hello,this is my own module![1028215.008381] Hello,this is myusefunc module.[1028215.008385] This is public module and used for another modules.[1028215.008386] Linux kernel communication.

通過(guò)打印信息可知,publicFunc函數(shù)以成功實(shí)現(xiàn)在其他內(nèi)核模塊內(nèi)調(diào)用。接下來(lái),我們卸載內(nèi)核模塊,再看下會(huì)發(fā)生什么?

[root@localhost tmp]# rmmod myexportfuncrmmod: ERROR: Module myexportfunc is in use by: myusefunc

報(bào)錯(cuò)了,很詫異吧,為什么會(huì)無(wú)法卸載呢,我們從報(bào)錯(cuò)信息中就可以看出端倪, myexportfunc模塊正在被myusefunc模塊使用,所以無(wú)法卸載。通過(guò)modinfo命令,我們也可以看出myusefunc模塊的依賴(lài)關(guān)系:

[root@localhost 24]# modinfo myusefunc.kofilename:       /tmp/tmp/24/myusefunc.kolicense:        GPLrhelversion:    8.7srcversion:     092199D11396603B6377902depends:        myexportfuncname:           myusefuncvermagic:       4.18.0-394.el8.x86_64 SMP mod_unload modversions

通過(guò)上述depends行的結(jié)果可以看出,myusefunc模塊依賴(lài)myexportfunc模塊。

因此卸載也是需要按照順序進(jìn)行,先卸載調(diào)用模塊,再卸載被調(diào)用模塊,方可保證卸載成功。

[root@localhost tmp]# rmmod myusefunc[root@localhost tmp]# rmmod myexportfunc

按照如上所說(shuō)進(jìn)行卸載,果然成功了,再通過(guò)dmesg查看打印的信息是什么,如下:

[root@localhost ~]# dmesg[  635.296204] Hello,this is my export module![  646.274636] Hello,this is myusefunc module.[  646.274655] This is public function and used for another modules.[  646.274657] Linux kernel communication.[  676.093397] Goodbye this is myusefunc module.[  683.385341] Goodbye,this is my export clean module![root@localhost ~]#

2、EXPORT_SYMBOL_GPL導(dǎo)出符號(hào)

同樣定義兩個(gè)源文件myexportfunc.cmyusefunc.c,分別放置在不同目錄;在myexportfunc.c文件中使用EXPORT_SYMBOL_GPL導(dǎo)出publicFunc函數(shù)以供myusefunc.c文件中的函數(shù)調(diào)用。myusefunc.c文件中要想成功調(diào)用publicFunc函數(shù),必須進(jìn)行extern聲明,否則編譯時(shí)會(huì)報(bào)錯(cuò)。源碼如下:

myexportfunc.c文件:

/* myexportfunc.c */#include < linux/module.h >#include < linux/kernel.h >#include < linux/init.h >char myOwnVar[30]="Linux kernel communication.";static int __init myfunc_init(void){    printk("Hello,this is my own module!\\n");    return 0;}static void __exit myfunc_exit(void){    printk("Goodbye,this is my own clean module!\\n");}void publicFunc(void){    printk(KERN_INFO "This is public module and used for another modules.\\n");}module_init(myfunc_init);module_exit(myfunc_exit);EXPORT_SYMBOL_GPL(publicFunc);EXPORT_SYMBOL(myOwnVar);MODULE_DESCRIPTION("First Personel Module");MODULE_AUTHOR("Lebron James");MODULE_LICENSE("GPL");

myexportfunc.c文件的Makefile文件:

ifneq ($(KERNELRELEASE),)$(info "2nd")obj-m:=myexportfunc.oelseKDIR :=/lib/modules/$(shell uname -r)/buildPWD  :=$(shell pwd)all:        $(info "1st")        make -C $(KDIR) M=$(PWD) modulesclean:        rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order *.modendif

myusefunc.c文件:

/* myusefunc.c */#include < linux/init.h >#include < linux/module.h >extern void publicFunc(void);extern char myOwnVar[30];void showVar(void);static int __init hello_init(void){        printk(KERN_INFO "Hello,this is myusefunc module.\\n");        publicFunc();        showVar();        return 0;}static void __exit hello_exit(void){        printk(KERN_INFO "Goodbye this is myusefunc module.\\n");}void showVar(void){        printk(KERN_INFO "%s\\n", myOwnVar);}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");

myusefunc.c文件的Makefile文件:

KBUILD_EXTRA_SYMBOLS += /tmp/tmp/Module.symversifneq ($(KERNELRELEASE),)$(info "2nd")obj-m:=myusefunc.oelseKDIR :=/lib/modules/$(shell uname -r)/buildPWD  :=$(shell pwd)all:        $(info "1st")        make -C $(KDIR) M=$(PWD) modulesclean:        rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order *.modendif

分別通過(guò)make命令編譯myexportfunc.cmyusefunc.c文件:

[root@localhost tmp]# ls24  Makefile  myexportfunc.c[root@localhost tmp]# make"1st"make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp modulesmake[1]: Entering directory "/usr/src/kernels/4.18.0-394.el8.x86_64""2nd"  CC [M]  /tmp/tmp/myexportfunc.o  Building modules, stage 2."2nd"  MODPOST 1 modules  CC      /tmp/tmp/myexportfunc.mod.o  LD [M]  /tmp/tmp/myexportfunc.komake[1]: Leaving directory "/usr/src/kernels/4.18.0-394.el8.x86_64"[root@localhost tmp]# cd 24[root@localhost 24]# lsMakefile  myusefunc.c[root@localhost 24]# vi myusefunc.c[root@localhost 24]# make"1st"make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp/24 modulesmake[1]: Entering directory "/usr/src/kernels/4.18.0-394.el8.x86_64""2nd"  CC [M]  /tmp/tmp/24/myusefunc.o  Building modules, stage 2."2nd"  MODPOST 1 modules  CC      /tmp/tmp/24/myusefunc.mod.o  LD [M]  /tmp/tmp/24/myusefunc.komake[1]: Leaving directory "/usr/src/kernels/4.18.0-394.el8.x86_64"[root@localhost 24]#[root@localhost 24]# cd ..[root@localhost tmp]# ls24  Makefile  modules.order  Module.symvers  myexportfunc.c  myexportfunc.ko  myexportfunc.mod.c  myexportfunc.mod.o  myexportfunc.o[root@localhost tmp]# insmod ./myexportfunc.ko[root@localhost tmp]#[root@localhost tmp]# cd 24[root@localhost 24]# lsMakefile  modules.order  Module.symvers  myusefunc.c  myusefunc.ko  myusefunc.mod.c  myusefunc.mod.o  myusefunc.o[root@localhost 24]# insmod ./myusefunc.ko[root@localhost 24]#[root@localhost 24]# cat /proc/kallsyms | grep publicFuncffffffffc0480040 r __ksymtab_publicFunc [myexportfunc]ffffffffc04800ed r __kstrtab_publicFunc [myexportfunc]ffffffffc047f000 t publicFunc   [myexportfunc] [root@localhost 24]# cat /proc/kallsyms | grep myOwnVarffffffffc0480030 r __ksymtab_myOwnVar   [myexportfunc]ffffffffc04800e4 r __kstrtab_myOwnVar   [myexportfunc]ffffffffc0481000 D myOwnVar     [myexportfunc][root@localhost 24]# dmesg[1039412.015206] Hello,this is my own module![1039426.559478] Hello,this is myusefunc module.[1039426.559482] This is public module and used for another modules.[1039426.559482] Linux kernel communication.

注:

使用EXPORT_SYMBOL_GPL導(dǎo)出的符號(hào)的模塊類(lèi)型為小寫(xiě)字母t,表示局部引用使用EXPORT_SYMBOL導(dǎo)出的符號(hào)的模塊類(lèi)型為大寫(xiě)字母D,表示全局引用

上述內(nèi)容顯示了成功在內(nèi)核模塊調(diào)用其他內(nèi)核模塊的函數(shù)或變量的過(guò)程,接下來(lái),讓我們一起看一下,哪些情況下會(huì)導(dǎo)致無(wú)法調(diào)用其他內(nèi)核模塊函數(shù)或變量,并且會(huì)報(bào)Unknown symbol錯(cuò)誤。

三、Unknown symbol錯(cuò)誤

Unknown symbol說(shuō)明 有些函數(shù)不認(rèn)識(shí)(未定義)。

1、使用EXPORT_SYMBOL導(dǎo)出符號(hào)

使用EXPORT_SYMBOL宏導(dǎo)出函數(shù)及變量的情形下,不插入模塊myexportfunc,直接插入模塊myusefunc,會(huì)出現(xiàn)Unknown symbol in module,原因在于此時(shí)內(nèi)核全局符號(hào)表中不存在publicFuncmyOwnVar符號(hào):

[root@localhost tmp]# lsmod | grep myexportfunc[root@localhost tmp]#[root@localhost tmp]# cd 24[root@localhost 24]# insmod myusefunc.koinsmod: ERROR: could not insert module myusefunc.ko: Unknown symbol in module #dmesg查看報(bào)錯(cuò)原因[root@localhost 24]# dmesg[1025403.614123] myusefunc: Unknown symbol publicFunc (err 0)[1025403.614144] myusefunc: Unknown symbol myOwnVar (err 0)

先插入模塊myexportfunc,再插入模塊myusefunc,通過(guò)dmesg查看,此時(shí)模塊myexportfunc中定義的publicFuncmyOwnVar符號(hào)成功被模塊myusefunc使用:

[root@localhost tmp]# insmod ./myexportfunc.ko[root@localhost tmp]# cd 24[root@localhost 24]# lsMakefile  modules.order  Module.symvers  myusefunc.c  myusefunc.ko  myusefunc.mod.c  myusefunc.mod.o  myusefunc.o[root@localhost 24]# insmod ./myusefunc.ko [root@localhost 24]# cat /proc/kallsyms | grep myOwnVarffffffffc0480030 r __ksymtab_myOwnVar   [myexportfunc]ffffffffc04800e4 r __kstrtab_myOwnVar   [myexportfunc]ffffffffc0481000 D myOwnVar     [myexportfunc][root@localhost 24]#[root@localhost 24]# cat /proc/kallsyms | grep publicFuncffffffffc0480040 r __ksymtab_publicFunc [myexportfunc]ffffffffc04800ed r __kstrtab_publicFunc [myexportfunc]ffffffffc047f000 T publicFunc   [myexportfunc][root@localhost 24]# dmesg[1025729.139236] Hello,this is my own module![1025739.579713] Hello,this is myusefunc module.[1025739.579717] This is public module and used for another modules.[1025739.579718] Linux kernel communication.

2、未使用EXPORT_SYMBOL導(dǎo)出符號(hào)

myexportfunc.c中的EXPORT_SYMBOL注釋掉,myexportfunc源碼文件修改如下:

/* myexportfunc.c */#include < linux/module.h >#include < linux/kernel.h >#include < linux/init.h >char myOwnVar[30]="Linux kernel communication.";static int __init myfunc_init(void){    printk("Hello,this is my own module!\\n");    return 0;}static void __exit myfunc_exit(void){    printk("Goodbye,this is my own clean module!\\n");}void publicFunc(void){    printk(KERN_INFO "This is public module and used for another modules.\\n");}module_init(myfunc_init);module_exit(myfunc_exit);//EXPORT_SYMBOL(publicFunc);//EXPORT_SYMBOL(myOwnVar);MODULE_DESCRIPTION("First Personel Module");MODULE_AUTHOR("Lebron James");MODULE_LICENSE("GPL");

重新通過(guò)make命令編譯myexportfuncmyusefunc模塊,myusefunc源文件、Makefile文件及編譯方法同上,首先插入模塊myexportfunc,此時(shí)全局符號(hào)表中的符號(hào)類(lèi)型為d和t,再插入模塊myusefunc報(bào)錯(cuò),無(wú)法訪(fǎng)問(wèn)模塊myexportfunc中的符號(hào)。

[root@localhost tmp]# insmod ./myexportfunc.ko[root@localhost tmp]# cat /proc/kallsyms | grep myOwnVarffffffffc0481000 d myOwnVar     [myexportfunc]   [root@localhost tmp]# cat /proc/kallsyms | grep publicFuncffffffffc047f00c t publicFunc   [myexportfunc][root@localhost tmp]# cd 24 [root@localhost 24]# make"1st"make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp/24 modulesmake[1]: Entering directory "/usr/src/kernels/4.18.0-394.el8.x86_64""2nd"  CC [M]  /tmp/tmp/24/myusefunc.o  Building modules, stage 2."2nd"  MODPOST 1 modulesWARNING: "publicFunc" [/tmp/tmp/24/myusefunc.ko] undefined!WARNING: "myOwnVar" [/tmp/tmp/24/myusefunc.ko] undefined!  CC      /tmp/tmp/24/myusefunc.mod.o  LD [M]  /tmp/tmp/24/myusefunc.komake[1]: Leaving directory "/usr/src/kernels/4.18.0-394.el8.x86_64"[root@localhost 24]# insmod ./myusefunc.koinsmod: ERROR: could not insert module ./myusefunc.ko: Unknown symbol in module [root@localhost 24]# dmesg[1027498.802299] Goodbye this is myusefunc module.[1027502.210478] Goodbye,this is my own clean module![1027507.431371] Hello,this is my own module![1027519.232574] myusefunc: Unknown symbol publicFunc (err 0)[1027519.232594] myusefunc: Unknown symbol myOwnVar (err 0)

原因在于,模塊類(lèi)型為小寫(xiě)字母d和t表示局部引用,定義在DataText,只能在模塊內(nèi)訪(fǎng)問(wèn)。模塊類(lèi)型為大寫(xiě)字母D和T表示全局引用,可以在模塊外訪(fǎng)問(wèn),其他類(lèi)型類(lèi)似。

3、使用EXPORT_SYMBOL_GPL導(dǎo)出符號(hào)

使用EXPORT_SYMBOL_GPL導(dǎo)出myexportfunc.c文件中的publicFunc函數(shù),修改myexportfunc.c源文件如下:

/* myexportfunc.c */#include < linux/module.h >#include < linux/kernel.h >#include < linux/init.h >char myOwnVar[30]="Linux kernel communication.";static int __init myfunc_init(void){    printk("Hello,this is my own module!\\n");    return 0;}static void __exit myfunc_exit(void){    printk("Goodbye,this is my own clean module!\\n");}void publicFunc(void){    printk(KERN_INFO "This is public module and used for another modules.\\n");}module_init(myfunc_init);module_exit(myfunc_exit);EXPORT_SYMBOL_GPL(publicFunc);EXPORT_SYMBOL(myOwnVar);MODULE_DESCRIPTION("First Personel Module");MODULE_AUTHOR("Lebron James");MODULE_LICENSE("GPL");

myusefunc.c中的MODULE_LICENSE("GPL")注釋掉,myusefunc.c源碼文件修改如下:

/* myusefunc.c */#include < linux/init.h >#include < linux/module.h >extern void publicFunc(void);extern char myOwnVar[30];void showVar(void);static int __init hello_init(void){        printk(KERN_INFO "Hello,this is myusefunc module.\\n");        publicFunc();        showVar();        return 0;}static void __exit hello_exit(void){        printk(KERN_INFO "Goodbye this is myusefunc module.\\n");}void showVar(void){        printk(KERN_INFO "%s\\n", myOwnVar);}module_init(hello_init);module_exit(hello_exit);//MODULE_LICENSE("GPL");

兩個(gè)模塊的Makefile文件均同上,分別通過(guò)make命令編譯myexportfunc.cmyusefunc.c文件,之后使用insmod命令先后插入兩個(gè)模塊,如下:

[root@localhost tmp]# insmod ./myexportfunc.ko[root@localhost tmp]# cd 24[root@localhost 24]# make"1st"make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp/24 modulesmake[1]: Entering directory "/usr/src/kernels/4.18.0-394.el8.x86_64""2nd"  CC [M]  /tmp/tmp/24/myusefunc.o  Building modules, stage 2."2nd"  MODPOST 1 modulesWARNING: modpost: missing MODULE_LICENSE() in /tmp/tmp/24/myusefunc.osee include/linux/module.h for more information  CC      /tmp/tmp/24/myusefunc.mod.o  LD [M]  /tmp/tmp/24/myusefunc.komake[1]: Leaving directory "/usr/src/kernels/4.18.0-394.el8.x86_64"[root@localhost 24]#[root@localhost 24]# insmod ./myusefunc.koinsmod: ERROR: could not insert module ./myusefunc.ko: Unknown symbol in module[root@localhost 24]# dmesg[1030402.772230] Hello,this is my own module![1030428.231104] myusefunc: Unknown symbol publicFunc (err 0)

通過(guò)上面結(jié)果可知,在被調(diào)用模塊使用EXPORT_SYMBOL_GPL宏導(dǎo)出函數(shù)或變量后,調(diào)用該函數(shù)或變量的調(diào)用模塊必須包含MODULE_LICENSE("GPL")宏,否則,在加載該模塊時(shí),將會(huì)報(bào)Unknown symbol錯(cuò)誤。即只有包含GPL許可權(quán)的模塊才能調(diào)用EXPORT_SYMBOL_GPL宏導(dǎo)出的符號(hào)。

License(許可證)

Linux是一款免費(fèi)的操作系統(tǒng),采用了GPL協(xié)議,允許用戶(hù)可以任意修改其源代碼。 GPL協(xié)議的主要內(nèi)容是軟件產(chǎn)品中即使使用了某個(gè)GPL協(xié)議產(chǎn)品提供的庫(kù), 衍生出一個(gè)新產(chǎn)品,該軟件產(chǎn)品都必須采用GPL協(xié)議,即必須是開(kāi)源和免費(fèi)使用的, 可見(jiàn)GPL協(xié)議具有傳染性。因此,我們可以在Linux使用各種各樣的免費(fèi)軟件。 在以后學(xué)習(xí)Linux的過(guò)程中,可能會(huì)發(fā)現(xiàn)我們安裝任何一款軟件,從來(lái)沒(méi)有30天試用期或者是要求輸入激活碼的。

內(nèi)核模塊許可證有 “GPL”,“GPL v2”,“GPL and additional rights”,“Dual SD/GPL”,“Dual MPL/GPL”,“Proprietary”

四、總結(jié)

如果你的模塊需要輸出符號(hào)給其他模塊使用,符號(hào)必須在模塊文件的全局部分輸出, 在任何函數(shù)之外, 因?yàn)楹甓x擴(kuò)展成一個(gè)特殊用途的并被期望是全局存取的變量的聲明。 這個(gè)變量存儲(chǔ)于模塊的一個(gè)特殊的可執(zhí)行部分( 一個(gè) "ELF 段" ), 內(nèi)核通過(guò)這個(gè)部分在加載時(shí)找到模塊輸出的變量。編譯生成ko模塊之后,用insmod命令加載此模塊到內(nèi)核。這個(gè)程序加載模塊的代碼段和數(shù)據(jù)段到內(nèi)核。

使用你的模塊輸出符號(hào)的其他模塊同樣通過(guò)insmod加載到內(nèi)核,insmod在加載的過(guò)程中使用公共內(nèi)核符號(hào)表來(lái)解析模塊中未定義的符號(hào)(即通過(guò)extern聲明的符號(hào)),公共內(nèi)核符號(hào)表中包含了所有的全局內(nèi)核項(xiàng)(即函數(shù)和變量)的地址,這是實(shí)現(xiàn)模塊化驅(qū)動(dòng)程序所必需的。

同時(shí)也可以導(dǎo)出自身模塊中的任何內(nèi)核符號(hào)到公共內(nèi)核符號(hào)表,如圖:

通常情況下,模塊只需實(shí)現(xiàn)自己的功能,而無(wú)需導(dǎo)出任何符號(hào)。但是,如果其他模塊需要從某個(gè)模塊中獲得好處時(shí),我們也可以導(dǎo)出符號(hào)。

驅(qū)動(dòng)也是存在于內(nèi)核空間的,它的每一個(gè)函數(shù)每一個(gè)變量都會(huì)有對(duì)應(yīng)的符號(hào),這部分符號(hào)也可以稱(chēng)作內(nèi)核符號(hào),它們不導(dǎo)出(EXPORT_SYMBOL)就只能為自身所用,導(dǎo)出后就可以成為公用,對(duì)于導(dǎo)出的那部分內(nèi)核符號(hào)就是我們常說(shuō)的內(nèi)核符號(hào)表。

EXPORT_SYMBOL使用方法

在模塊函數(shù)定義之后使用EXPORT_SYMBOL(函數(shù)名);在調(diào)用該函數(shù)的模塊中使用extern對(duì)之聲明;首先加載定義該函數(shù)的模塊,再加載調(diào)用該函數(shù)的模塊?!灸K加載順序的前后要求,一般就是依賴(lài)于符號(hào)調(diào)用】

insmod的時(shí)候并不是所有的函數(shù)都得到內(nèi)核符號(hào)表去尋找對(duì)應(yīng)的符號(hào),每一個(gè)驅(qū)動(dòng)在自己分配的空間里也會(huì)存儲(chǔ)一份符號(hào)表,里面有關(guān)于這個(gè)驅(qū)動(dòng)里使用到的變量以及函數(shù)的一些符號(hào),首先驅(qū)動(dòng)會(huì)在這里面找,如果發(fā)現(xiàn)找不到就會(huì)去公共內(nèi)核符號(hào)表中搜索,搜索到了則該模塊加載成功,搜索不到則該模塊加載失敗。

內(nèi)核默認(rèn)情況下,是不會(huì)在模塊加載后把模塊中的非靜態(tài)全局變量以及非靜態(tài)函數(shù)自動(dòng)導(dǎo)出到內(nèi)核符號(hào)表中的,需要顯式調(diào)用宏EXPORT_SYMBOL才能導(dǎo)出。對(duì)于一個(gè)模塊來(lái)講,如果僅依靠自身就可以實(shí)現(xiàn)自已的功能,那么可以不需要要導(dǎo)出任何符號(hào),只有其他模塊中需要使用到該模塊提供的函數(shù)時(shí),就必須要進(jìn)行導(dǎo)出操作。

標(biāo)簽:

上一篇:RTOS實(shí)現(xiàn)雙核MCU消息通信
下一篇:最后一頁(yè)