1. 程式人生 > >Linux核心一個模組調另一個模組的函式

Linux核心一個模組調另一個模組的函式

  前幾天,需要在一個核心模組A中新增一個新功能。這個新功能用到了另一個核心模組B中的函式C。我將相關的標頭檔案include之後,載入A模組時,總是出錯,說用到的那個函式C找不著。

  怎麼回事?以前沒接觸過核心程式設計的,找了個小牛問了一下,原來是Linux2.6核心不會自動的將非static 函式和變數匯入到kernel 空間,需要用到EXPORT_SYMBOL來對函式做一下標記才行。

 /* in module B*/

void C()

{

......

}

EXPORT_SYMBOL(C);

/*in module A*/

void func_in_A()

{

    extern void c(void);

    ......

    C();

   ......

}

OK了,這下子編譯的時候,雖然還會報warning(不報才怪了),但是insmod時,不會出錯了。

上網上找了找別人寫的這方面的文章,貼到下面,用得著的朋友,都看看吧,也不用到處找了

一個模組mod1中定義一個函式func1;在另外一個模組mod2中定義一個函式func2,func2呼叫func1。
在模組mod1中,EXPORT_SYMBOL(func1);
在模組mod2中,extern int func1();
就可以在mod2中呼叫func1了。

=================================

EXPORT_SYMBOL只出現在2.6核心中,在2.4核心預設的非static 函式和變數都會自動匯入到kernel 空間的, 都不用EXPORT_SYMBOL() 做標記的。
2.6就必須用EXPORT_SYMBOL() 來匯出來(因為2.6預設不到處所有的符號)。

1、EXPORT_SYMBOL的作用是什麼?
EXPORT_SYMBOL標籤內定義的函式或者符號對全部核心程式碼公開,不用修改核心程式碼就可以在您的核心模組中直接呼叫,即使用EXPORT_SYMBOL可以將一個函式以符號的方式匯出給其他模組使用。
這裡要和System.map做一下對比:
System.map 中的是連線時的函式地址。連線完成以後,在2.6核心執行過程中,是不知道哪個符號在哪個地址的。
EXPORT_SYMBOL 的符號, 是把這些符號和對應的地址儲存起來,在核心執行的過程中,可以找到這些符號對應的地址。而模組在載入過程中,其本質就是能動態連線到核心,如果在模組中引用了核心或其它模組的符號,就要EXPORT_SYMBOL這些符號,這樣才能找到對應的地址連線。

2、使用方法
   第一、在模組函式定義之後使用EXPORT_SYMBOL(函式名)
   第二、在掉用該函式的模組中使用extern對之宣告
   第三、首先載入定義該函式的模組,再載入呼叫該函式的模組

另外,在編譯呼叫某匯出函式的模組時,往往會有WARNING: "****" [**********] undefined!
使用dmesg命令後會看到相同的資訊。開始我以為只要有這個錯誤就不能載入模組,後來上網查了一下,發現這主要是因為在編譯連線的時候還沒有和核心打交道,當然找不到symbol了,但是由於你生成的是一個核心模組,所以LD不提示error,而是給出一個warning,寄希望於在insmod的時候,核心能夠把這個symbol連線上。

參考資料:

-------------------------------------------------------------

一個模組mod1中定義一個函式func1;在另外一個模組mod2中定義一個函式func2,func2呼叫func1。
在模組mod1中,EXPORT_SYMBOL(func1);
在模組mod2中,extern int func1();
就可以在mod2中呼叫func1了。

mod1.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>

static int func1(void)
{
        printk("In Func: %s...\n",__func__);
        return 0;
}

EXPORT_SYMBOL(func1);

static int __init hello_init(void)
{
        printk("Module 1,Init!\n");
        return 0;
}

static void __exit hello_exit(void)
{
        printk("Module 1,Exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);


#############################################################
mod2.c
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>

static int func2(void)
{
        extern int func1(void);
        func1();
        printk("In Func: %s...\n",__func__);
        return 0;
}

static int __init hello_init(void)
{
        printk("Module 2,Init!\n");
        func2();
        return 0;
}

static void __exit hello_exit(void)
{
        printk("Module 2,Exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);

################################################################
Makefile
ifneq ($(KERNELRELEASE),)
obj-m   := XXXX.o
else
KDIR    := /lib/modules/$(shell uname -r)/build
PWD             := $(shell pwd)

default:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
        rm -rf Module.symvers *.ko *.o *.mod.c .*.cmd .tmp_versions

endif

################################################################

#insmod ./mod1.ko
#insmod ./mod2.ko
#rmmod mod2
#rmmod mod1

Jan 11 11:59:17 wangyao-desktop kernel: [ 9886.801010] Module 2,Exit!
Jan 11 11:59:21 wangyao-desktop kernel: [ 9891.450214] Module 1,Exit!
Jan 11 12:05:29 wangyao-desktop kernel: [10258.385014] Module 1,Init!
Jan 11 12:05:38 wangyao-desktop kernel: [10267.465923] Module 2,Init!
Jan 11 12:05:38 wangyao-desktop kernel: [10267.465928] In Func: func1...
Jan 11 12:05:38 wangyao-desktop kernel: [10267.465930] In Func: func2...
Jan 11 12:05:50 wangyao-desktop kernel: [10280.091755] Module 2,Exit!
Jan 11 12:05:57 wangyao-desktop kernel: [10287.332596] Module 1,Exit!

可見,在mod2中的func2函式成功的呼叫了mod1中的func1函式。

注意:
在編譯mod2的時候,出現一個WARNING:
[email protected]:~/modules/export_symbol/mod2# make
make -C /lib/modules/2.6.22-14-generic/build SUBDIRS=/root/modules/export_symbol/mod2 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.22-14-generic'
Building modules, stage 2.
MODPOST 1 modules
WARNING: "func1" [/root/modules/export_symbol/mod2/mod2.ko] undefined!
make[1]: Leaving directory `/usr/src/linux-headers-2.6.22-14-generic'


這主要是因為在編譯連線的時候還沒有和核心打交道,當然找不到symbol了,但是由於你生成的是一個核心模組,所以LD不提示error,而是給出一個warning,寄希望於在insmod的時候,核心能夠把這個symbol連線上。