Linux內(nèi)核模塊間通訊方法非常的多,最便捷的方法莫過于函數(shù)或變量符號(hào)導(dǎo)出,然后直接調(diào)用。默認(rèn)情況下,模塊與模塊之間、模塊與內(nèi)核之間的全局變量是相互獨(dú)立的,只有通過EXPORT_SYMBOL
將模塊導(dǎo)出才能對(duì)其他模塊或內(nèi)核可見。
符號(hào)導(dǎo)出函數(shù)
EXPORT_SYMBOL()
:括號(hào)中定義的函數(shù)或變量對(duì)全部?jī)?nèi)核代碼公開EXPORT_SYMBOL_GPL()
和EXPORT_SYMBOL
類似,但范圍只適合GPL許可的模塊進(jìn)行調(diào)用
一、內(nèi)核符號(hào)表
Linux kallsyms,即內(nèi)核符號(hào)表,其中會(huì)列出所有的Linux內(nèi)核中的導(dǎo)出符號(hào),在用戶態(tài)下可以通過/proc/kallsyms
訪問,此時(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_SYMBOL
或EXPORT_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)表類型
內(nèi)核符號(hào)表就是在內(nèi)核內(nèi)部函數(shù)或變量中可供外部引用的函數(shù)和變量的符號(hào)表(/proc/kallsyms),表格如下:
符號(hào)類型 | 名稱 | 說明 |
---|---|---|
A | Absolute | 符號(hào)的值是絕對(duì)值,并且在進(jìn)一步鏈接過程中不會(huì)被改變 |
B | BSS | 符號(hào)在未初始化數(shù)據(jù)區(qū)或區(qū)(section)中,即在BSS段中 |
C | Common | 符號(hào)是公共的。公共符號(hào)是未初始化的數(shù)據(jù)。在鏈接時(shí),多個(gè)公共符號(hào)可能具有同一名稱。如果該符號(hào)定義在其他地方,則公共符號(hào)被看作是未定義的引用 |
D | Data | 符號(hào)在已初始化數(shù)據(jù)區(qū)中 |
G | Global | 符號(hào)是在小對(duì)象已初始化數(shù)據(jù)區(qū)中的符號(hào)。某些目標(biāo)文件的格式允許對(duì)小數(shù)據(jù)對(duì)象(例如一個(gè)全局整型變量)可進(jìn)行更有效的訪問 |
I | Inderect | 符號(hào)是對(duì)另一個(gè)符號(hào)的間接引用 |
N | Debugging | 符號(hào)是一個(gè)調(diào)試符號(hào) |
R | Read only | 符號(hào)在一個(gè)只讀數(shù)據(jù)區(qū)中 |
S | Small | 符號(hào)是小對(duì)象未初始化數(shù)據(jù)區(qū)中的符號(hào) |
T | Text | 符號(hào)是代碼區(qū)中的符號(hào) |
U | Undefined | 符號(hào)是外部的,并且其值為0(未定義) |
V | Weaksymbol | 弱符號(hào) |
W | Weaksymbol | 弱符號(hào) |
- | Stabs | 符號(hào)是a.out目標(biāo)文件中的一個(gè)stab符號(hào),用于保存調(diào)試信息 |
? | Unknown | 符號(hào)的類型未知,或者與具體文件格式有關(guān) |
注 :符號(hào)屬性,小寫表示局部符號(hào),大寫表示全局符號(hào)
二、Linux內(nèi)核符號(hào)導(dǎo)出
1、EXPORT_SYMBOL導(dǎo)出符號(hào)
這里我們定義兩個(gè)源文件myexportfunc.c
和myusefunc.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!
");
return 0;
}
static void __exit myfunc_exit(void)
{
printk("Goodbye,this is my own clean module!
");
}
void publicFunc(void)
{
printk(KERN_INFO "This is public module and used for another modules.
");
}
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.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order *.mod
endif
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.
");
publicFunc();
showVar();
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye this is myusefunc module.
");
}
void showVar(void)
{
printk(KERN_INFO "%s
", myOwnVar);
}
module_init(hello_init);
module_exit(hello_exit);
myusefunc.c
文件的Makefile
文件:
KBUILD_EXTRA_SYMBOLS += /tmp/tmp/Module.symvers
ifneq ($(KERNELRELEASE),)
$(info "2nd")
obj-m:=myusefunc.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
all:
$(info "1st")
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.order *.mod
endif
注:
KBUILD_EXTRA_SYMBOLS
用來告訴內(nèi)核當(dāng)前module
需要引用另外一個(gè)module
導(dǎo)出的符號(hào)。KBUILD_EXTRA_SYMBOLS
后需要寫絕對(duì)路徑,相對(duì)路徑會(huì)出錯(cuò),因?yàn)?code>scripts/mod/modpost執(zhí)行時(shí), 以其在內(nèi)核目錄的路徑為起始點(diǎn)進(jìn)行解析。
分別通過make
命令編譯myexportfunc.c
和myusefunc.c
文件:
[root@localhost tmp]# make
"1st"
make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp modules
make[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.ko
make[1]: Leaving directory '/usr/src/kernels/4.18.0-394.el8.x86_64'
[root@localhost tmp]# ls -l
total 488
drwxr-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]# ls
Makefile myusefunc.c
[root@localhost 24]# make
"1st"
make -C /lib/modules/4.18.0-394.el8.x86_64/build M=/tmp/tmp/24 modules
make[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.ko
make[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 -l
total 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