内核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函数的使用:

#include 
#include 

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

#include 
#include 

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文件:
root@ubuntu:/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'
root@ubuntu:/usr/src/linux-2.6.39/driver/export/moduleb# vim moduleb.c 
#加载模块A成功,加载模块B失败;
root@ubuntu:/usr/src/linux-2.6.39/driver/export/moduleb# insmod ../modulea/modulea.ko 
root@ubuntu:/usr/src/linux-2.6.39/driver/export/moduleb# insmod moduleb.ko 
insmod: ERROR: could not insert module moduleb.ko: Invalid parameters

你可能感兴趣的:(内核,模块)