編寫C程序時,如果需要使用某個外部的函數,通常的做法是 #include 包含該函數原型(prototype)的頭文件,然後在程序中進行調用。經過編譯鏈接後,程序就能順利調用該函數。但是對於內核模塊來說,這種方法並不適用,因此Linux內核提供了一種機制——內核模塊符號表機制。即使用 EXPORT_SYMBOL 標簽將模塊中的函數對整個內核公開,因此導出的函數不用修改內核代碼就可以被其他內核模塊所調用。
也就是說,使用 EXPORT_SYMBOL 可以將一個函數以符號的方式導出給其他模塊使用。下面以一個簡單的例子來說明如何使用 EXPORT_SYMBOL。 我們以導出符號 test_add 為例,在適當的位置創建 add.c 和 Makefile 文件,內容如下:
【add.c】
[code]#include <linux/module.h> int test_add(int x, int y) { return x+y; } EXPORT_SYMBOL(test_add); MODULE_LICENSE("Dual BSD/GPL");【Makefile】
[code]obj-m += add.o KERN_VER := $(shell uname -r) KERN_DIR = /lib/modules/$(KERN_VER)/build modules: $(MAKE) -C $(KERN_DIR) M=`pwd` modules clean: $(MAKE) -C $(KERN_DIR) M=`pwd` modules clean執行 make 命令後,生成 add.ko,執行命令 insmod add.ko 加載模塊。
確認 add 模塊加載成功:
[code]命令: cat /proc/modules | grep add 輸出: add 12465 0 - Live 0xf88f9000 (O)確認 test_add 符號導出成功:
[code]命令: cat /proc/kallsyms | grep test_add 輸出: f88fa024 r __ksymtab_test_add [add] f88fa030 r __kstrtab_test_add [add] f88fa02c r __kcrctab_test_add [add] f88f9000 T test_add [add]接下來,在適當的位置創建 test.c 和 Makefile 文件進行測試,內容如下:
【test.c】
[code]#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> /* 導出的符號可以被其他模塊使用,不過使用之前一定要聲明一下 */ int test_add(int x, int y); static int __init test_init(void) { printk(KERN_ALERT "test_init\n"); printk(KERN_ALERT "%d\n", test_add(12, 13)); return 0; } static void __exit test_exit(void) { printk(KERN_ALERT "test_exit\n"); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("Dual BSD/GPL");【Makefile】
[code]obj-m += test.o KERN_VER := $(shell uname -r) KERN_DIR = /lib/modules/$(KERN_VER)/build modules: $(MAKE) -C $(KERN_DIR) M=`pwd` modules clean: $(MAKE) -C $(KERN_DIR) M=`pwd` modules clean執行 make 命令,發現如下警告:
[code]WARNING: "test_add" [/home/walle/workspace/export_symbol/test/test.ko] undefined!如果我們忽略警告,直接執行 insmod test.ko,發現模塊加載失敗!
[code][806556.012242] test: no symbol version for test_add [806556.012258] test: Unknown symbol test_add (err -22)所以我們必須處理這個警告,而出現這樣警告的原因是 test 模塊不知道 test_add 的符號信息,解決辦法有兩個:
① 把 add 模塊的 Module.symvers 放到 test 模塊所在目錄下,重新編譯 test 模塊,test_add 的符號信息就會鏈接進去。
② 在 test 模塊的 Makefile 中使用 KBUILD_EXTRA_SYMBOLS 指定 add 模塊的 Module.symvers。
[code]KBUILD_EXTRA_SYMBOLS = /home/walle/workspace/export_symbol/add/Module.symvers
重新 make ,再次執行 insmod test.ko 加載模塊。
[code][806582.562028] test_init [806582.562074] 25
可以看到,test 模塊已經成功調用 add 模塊的 test_add 函數了!(輸出結果25)
另外,也可以使用 EXPORT_SYMBOL_GPL 進行符號導出,但只適用於包含GPL許可權的模塊。(它們定義在 include/linux/export.h)