1. 程式人生 > >核心EXPORT_SYMBOL函式講解(一)

核心EXPORT_SYMBOL函式講解(一)

EXPORT_SYMBOL巨集定義原型:

#define EXPORT_SYMBOL(sym)                                      \
        __EXPORT_SYMBOL(sym, "")

其中__EXPORT_SYMBOL原型如下:

/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec)                               \
        extern typeof(sym) sym;                                 \
        __CRC_SYMBOL(sym, sec)                                  \
        static const char __kstrtab_##sym[]                     \
        __attribute__((section("__ksymtab_strings"), aligned(1))) \
        = MODULE_SYMBOL_PREFIX #sym;                            \
        static const struct kernel_symbol __ksymtab_##sym       \
        __used                                                  \
        __attribute__((section("__ksymtab" sec), unused))       \
        = { (unsigned long)&sym, __kstrtab_##sym }

__EXPORT_SYMBOL巨集定義主要有四個方面:

	1.獲取匯出的符號的名稱,以字串表示
	2.把獲取到的以字串表示的名稱以及值放入,__ksymtab_+匯出的符號為變數的struct kernel_symbol變數中;
	3.在編譯工程中,把struct kernel_symbol編譯進入以"ksymtab"為開頭的符號表中;
	4.核心在載入模組時候先查詢已經載入過的模組的符號表,如果不存在則繼續載入模組

EXPORT_SYMBOL_GPL巨集定義與EXPORT_SYMBOL巨集定義差不多,不過是編譯過程中和載入過程中把符號表加入了以"ksymtab_gpl"為區域的檔案中或者記憶體中。
其中struct kernel_symbol函式原型定義如下:

		struct kernel_symbol
		{
		        unsigned long value;
		        const char *name;
		};

從定義可以看出使用EXPORT_SYMBOL函式就是把匯出的符號以符號值+符號的字串表示的形式表示的;

EXPORT_SYMBOL函式的使用:
<modula.c>

#include <linux/init.h>
#include <linux/module.h>

static inline int
module_a_init_func(void)
{
        printk
("this is module a init func\n"); return 0; } static inline void module_a_exit_func(void) { printk("this is module a exit func\n"); } static inline int __init module_a_init(void) { printk("this is module a init\n"); return module_a_init_func(); } static inline void __exit module_a_exit(void) { printk("this is module a exit\n"); module_a_exit_func(); } EXPORT_SYMBOL(module_a_init_func); EXPORT_SYMBOL(module_a_exit_func); module_init(module_a_init); module_exit(module_a_exit);

modulea’s Makefile

KERN_DIR = /lib/modules/`uname -r`/build/
obj-m := modulea.o
all:
        make -C $(KERN_DIR) M=$(shell pwd) modules
clean:
        make -C $(KERN_DIR) M=$(shell pwd) modules clean

<moudleb.c>

#include <linux/init.h>
#include <linux/module.h>

extern int
module_a_init_func(void);

extern void
module_a_exit_func(void);

static inline int __init
module_b_init(void)
{
        return module_a_init_func();
}

static inline int __exit
module_b_exit(void)
{
        module_a_exit_func();
}

module_init(module_b_init);
module_exit(module_b_exit);

moduleb’s Makefile

KERN_DIR = /lib/modules/`uname -r`/build/
obj-m := moduleb.o
KBUILD_EXTRA_SYMBOLS+=/usr/src/linux-2.6.39/driver/export/modulea/Module.symvers
export KBUILD_EXTRA_SYMBOLS
all:
        make -C ../modulea/
        make -C $(KERN_DIR) M=$(shell pwd) modules
clean:
        make -C $(KERN_DIR) M=$(shell pwd) modules clean

其中,“KBUILD_EXTRA_SYMBOLS+=/usr/src/linux-2.6.39/driver/export/modulea/Module.symvers“的模組A的Modules.symvers路徑是絕對路徑,不能是相對路徑;相對路徑會發生如下問題:

//都能夠編譯成.ko檔案:
[email protected]:/usr/src/linux-2.6.39/driver/export/moduleb# make
make -C ../modulea/
make[1]: Entering directory `/usr/src/linux-2.6.39/driver/export/modulea'
make -C /lib/modules/`uname -r`/build/ M=/usr/src/linux-2.6.39/driver/export/modulea modules
make[2]: Entering directory `/usr/src/linux-headers-3.13.0-160-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[2]: Leaving directory `/usr/src/linux-headers-3.13.0-160-generic'
make[1]: Leaving directory `/usr/src/linux-2.6.39/driver/export/modulea'
make -C /lib/modules/`uname -r`/build/ M=/usr/src/linux-2.6.39/driver/export/moduleb modules
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-160-generic'
  CC [M]  /usr/src/linux-2.6.39/driver/export/moduleb/moduleb.o
/usr/src/linux-2.6.39/driver/export/moduleb/moduleb.c: In function ‘module_b_exit’:
/usr/src/linux-2.6.39/driver/export/moduleb/moduleb.c:20:1: warning: no return statement in function returning non-void [-Wreturn-type]
 }
 ^
In file included from /usr/src/linux-2.6.39/driver/export/moduleb/moduleb.c:1:0:
/usr/src/linux-2.6.39/driver/export/moduleb/moduleb.c: In function ‘__exittest’:
include/linux/init.h:303:4: warning: return from incompatible pointer type [enabled by default]
  { return exitfn; }     \
    ^
/usr/src/linux-2.6.39/driver/export/moduleb/moduleb.c:23:1: note: in expansion of macro ‘module_exit’
 module_exit(module_b_exit);
 ^
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "module_a_exit_func" [/usr/src/linux-2.6.39/driver/export/moduleb/moduleb.ko] undefined!
WARNING: "module_a_init_func" [/usr/src/linux-2.6.39/driver/export/moduleb/moduleb.ko] undefined!
  CC      /usr/src/linux-2.6.39/driver/export/moduleb/moduleb.mod.o
  LD [M]  /usr/src/linux-2.6.39/driver/export/moduleb/moduleb.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-160-generic'
[email protected]:/usr/src/linux-2.6.39/driver/export/moduleb# vim moduleb.c 
#載入模組A成功,載入模組B失敗;
[email protected]:/usr/src/linux-2.6.39/driver/export/moduleb# insmod ../modulea/modulea.ko 
[email protected]:/usr/src/linux-2.6.39/driver/export/moduleb# insmod moduleb.ko 
insmod: ERROR: could not insert module moduleb.ko: Invalid parameters