linux 核心模組程式設計之核心符號匯出(五)
/proc/kallsyms 記錄了核心中所有匯出的符號的名字與地址
我們需要編譯2個核心模組,然後其中一個核心模組去呼叫另一個核心模組中的函式
hello.c程式碼如下
#include <linux/module.h> #include <linux/init.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Xie"); MODULE_DESCRIPTION("Hello World Module"); MODULE_ALIAS("a simplest module"); extern int add_integar(int a, int b); extern int sub_integer(int a, int b); static int __init hello_init() { int res = add_integar(1, 2); printk("add[%d]\n",res); return 0; } static void __exit hello_exit() { int res = sub_integer(2, 1); printk("sub[%d]\n",res); } module_init(hello_init); module_exit(hello_exit);
從這可以看出我們的hello.c中呼叫了2個函式 add_integar和 sub_integer,這2個函式我們在另一個模組中實現
calculate.c的程式碼如下
#include <linux/module.h> #include <linux/init.h> MODULE_LICENSE("GPL"); int add_integar(int a, int b) { return a+b; } int sub_integer(int a, int b) { return a-b; } static int __init sym_init() { return 0; } static void __exit sym_exit() { } module_init(sym_init); module_exit(sym_exit); EXPORT_SYMBOL(add_integar);//匯出函式,供hello.c呼叫 EXPORT_SYMBOL(sub_integer);//匯出函式,供hello.c呼叫
calculate.c對應的makefile 如下
ifneq ($(KERNELRELEASE),)
obj-m := calculate.o
else
KERNELDIR ?= /home/grb/grb/arm/linux-2.6.38/
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *~ *.order
endif
然後我們就可以將我們的模組拷貝到我們的開發板上執行測試了。
2個模組我們得先安裝calculate.ko ,不然的話hello.ko會因為找不到函式的實現而報錯,測試結果如下
核心符號匯出的使用
EXPORT_SYMBOL(符號名)
EXPORT_SYMBOL_GPL(符號名)
其中EXPORT_SYMBOL_GPL只能用於包含GPL許可證的模組
常見問題:版本不匹配
核心模組的版本由其所依賴的核心程式碼版本所決定,在載入核心模組時,insmod程式會將核心模組的版本與當前正在執行的核心版本比較,如果不一致,就會出現下面的錯誤:
insmod hello.ko
disagrees about version of symbol struct_module
insmod: error inserting 'hello.ko': -1 Invalid module format
解決方法:
1、使用modprobe --force-modversion強行插入(不推薦)
2、確保編譯核心模組時,所依賴的核心程式碼版本等於當前正在執行的核心,可通過uname -r檢視當前執行的核心版本
有一種投機取巧的方式,就是修改/home/grb/grb/arm/linux-2.6.38/Makefile 檔案中的版本號,如下
前面幾行就是他的版本號,這種方法很容易出問題,所以不推薦這種方法。
核心列印優先順序
在<linux/kernel.h>中定義了8種記錄級別。按照優先級別遞減的順序分別是:
KERN_EMERG "<0>" 用於緊急訊息,常常是那些崩潰前的訊息。
KERN_ALERT "<1>" 需要立刻行動的訊息
KERN_CRIT "<2>" 嚴重情況
KERN_ERR "<3>" 錯誤情況
如果沒有指定訊息的級別,printk()會使用預設的DEFAULT_MESSAGE_LOGLEVEL,他是一個在kernel/printk.c中定義的整數