1. 程式人生 > >linux 核心模組程式設計之核心符號匯出(五)

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


分別編譯完之後我們會得到一個hello.ko檔案和calculate.ko檔案


然後我們就可以將我們的模組拷貝到我們的開發板上執行測試了。

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中定義的整數