程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> EXPORT_SYMBOL解析

EXPORT_SYMBOL解析

編輯:C++入門知識

一般我們編寫C程序時,要調用某個文件中的函數,需要在本文件中包含聲明有被調用函數的頭文件,然後編譯連接後,方能找到調用函數。對於模塊依賴的情況,不能簡單的使用上面的方法,內核提供了一個機制,就是EXPORT_SYMBOL標簽內定義的函數或者符號對全部內核代碼公開,不用修改內核代碼就可以在您的內核模塊中直接調用,即使用EXPORT_SYMBOL可以將一個函數以符號的方式導出給其他模塊使用。您還可以手工修改內核源代碼來導出另外的函數,用於重新編譯並加載新內核後的測試。


[cpp]
include/module.h: 
  
struct kernel_symbol  

    unsigned long value;    
    const char *name; 
}; 
/* For every exported symbol, place a struct in the __ksymtab section */ 
#define __EXPORT_SYMBOL(sym, sec)               \  
    __CRC_SYMBOL(sym, sec)                  \ 
    static const char __kstrtab_##sym[]         \ 
    __attribute__((section("__ksymtab_strings")))       \ 
    = MODULE_SYMBOL_PREFIX #sym;                        \ 
    static const struct kernel_symbol __ksymtab_##sym   \ 
    __attribute_used__                  \ 
    __attribute__((section("__ksymtab" sec), unused))   \ 
    = { (unsigned long)&sym, __kstrtab_##sym } 
 
#define EXPORT_SYMBOL(sym)                  \  
    __EXPORT_SYMBOL(sym, "") 
 
#define EXPORT_SYMBOL_GPL(sym)                  \  
    __EXPORT_SYMBOL(sym, "_gpl") 
 
#endif 

include/module.h:
 
struct kernel_symbol
{
    unsigned long value;  
    const char *name;
};
/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec)               \
    __CRC_SYMBOL(sym, sec)                  \
    static const char __kstrtab_##sym[]         \
    __attribute__((section("__ksymtab_strings")))       \
    = MODULE_SYMBOL_PREFIX #sym;                        \
    static const struct kernel_symbol __ksymtab_##sym   \
    __attribute_used__                  \
    __attribute__((section("__ksymtab" sec), unused))   \
    = { (unsigned long)&sym, __kstrtab_##sym }

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

#define EXPORT_SYMBOL_GPL(sym)                  \
    __EXPORT_SYMBOL(sym, "_gpl")

#endif
下面是這種方法是演示:

 \
 


第一個模塊文件如下:

[lingyun@localhost export_symbol]$ ls
mod1  mod2
[lingyun@localhost export_symbol]$ cd mod1/
[lingyun@localhost mod1]$ ls
Makefile  mod_a.c
[lingyun@localhost mod1]$ vim mod_a.c
 mod_a.c                                                                                                           

[cpp]
/*********************************************************************************
 *      Copyright:  (C) 2013 fulinux<[email protected]
 *                  All rights reserved.
 *
 *       Filename:  mod_a.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(07/12/2013~)
 *         Author:  fulinux <[email protected]>
 *      ChangeLog:  1, Release initial version on "07/12/2013 10:06:50 AM"
 *                 
 ********************************************************************************/ 
 
 
#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); 
 
 
MODULE_LICENSE("GPL"); 

/*********************************************************************************
 *      Copyright:  (C) 2013 fulinux<[email protected]>
 *                  All rights reserved.
 *
 *       Filename:  mod_a.c
 *    Description:  This file
 *                
 *        Version:  1.0.0(07/12/2013~)
 *         Author:  fulinux <[email protected]>
 *      ChangeLog:  1, Release initial version on "07/12/2013 10:06:50 AM"
 *                
 ********************************************************************************/


#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);


MODULE_LICENSE("GPL");
其中EXPORT_SYMBOL(func1)導出func1函數符號,保存函數地址和名稱.

這個模塊的第一個Makefile文件:

[lingyun@localhost mod1]$ ls
Makefile  mod_a.c
[lingyun@localhost mod1]$ vim Makefile

 

[cpp]
obj-m:=mod1.o 
mod1-y:=mod_a.o 
 
KERNELDIR := /lib/modules/$(shell uname -r)/build 
 
PWD:=$(shell pwd) 
 
modules: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
 
modules_install: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 
clean: 
    rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET) 

obj-m:=mod1.o
mod1-y:=mod_a.o

KERNELDIR := /lib/modules/$(shell uname -r)/build

PWD:=$(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
    rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET)

其中內嵌對象 - obj-y,可加載模塊 - obj-m,KERNELDIR指向指向內核代碼目錄。

編譯編譯並加載:

[lingyun@localhost mod1]$ ls
Makefile  mod_a.c
[lingyun@localhost mod1]$ make
make -C /lib/modules/2.6.32-279.el6.x86_64/build  M=/usr/local/src/lingyun/fulinux/export_symbol/mod1 modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
  CC [M]  /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod_a.o
  LD [M]  /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.mod.o
  LD [M]  /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.ko.unsigned
  NO SIGN [M] /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'


[lingyun@localhost mod1]$ sudo insmod mod1.ko


[lingyun@localhost mod1]$ cat /proc/kallsyms | grep func1
0000000000000000 r __ksymtab_func1      [mod1]
0000000000000000 r __kstrtab_func1      [mod1]
0000000000000000 r __kcrctab_func1      [mod1]
0000000000000000 T func1        [mod1]
[lingyun@localhost mod1]$


[lingyun@localhost mod1]$ dmesg | grep Module
- User ID: CentOS (Kernel Module GPG key)
Module 1, Init!

 

 

第二個模塊的文件如下:

[lingyun@localhost mod1]$ cd ../mod2/
[lingyun@localhost mod2]$ vim mod_b.c

 

[cpp]
/*********************************************************************************
 *      Copyright:  (C) 2013 fulinux<[email protected]
 *                  All rights reserved.
 *
 *       Filename:  mod_b.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(07/12/2013~)
 *         Author:  fulinux <[email protected]>
 *      ChangeLog:  1, Release initial version on "07/12/2013 10:29:55 AM"
 *                 
 ********************************************************************************/ 
 
#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); 
 
MODULE_LICENSE("GPL"); 

/*********************************************************************************
 *      Copyright:  (C) 2013 fulinux<[email protected]>
 *                  All rights reserved.
 *
 *       Filename:  mod_b.c
 *    Description:  This file
 *                
 *        Version:  1.0.0(07/12/2013~)
 *         Author:  fulinux <[email protected]>
 *      ChangeLog:  1, Release initial version on "07/12/2013 10:29:55 AM"
 *                
 ********************************************************************************/

#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);

MODULE_LICENSE("GPL");


在這裡調用了第一個模塊中的func1函數。

對應的Makefile文件:

[lingyun@localhost mod2]$ vim Makefile

 

[cpp]
obj-m:=mod2.o 
mod2-y:=mod_b.o 
 
KERNELDIR := /lib/modules/$(shell uname -r)/build 
 
PWD:=$(shell pwd) 
 
modules: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
 
modules_install: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 
clean: 
    rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET) 

obj-m:=mod2.o
mod2-y:=mod_b.o

KERNELDIR := /lib/modules/$(shell uname -r)/build

PWD:=$(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
    rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET)

[lingyun@localhost mod2]$ make
make -C /lib/modules/2.6.32-279.el6.x86_64/build  M=/usr/local/src/lingyun/fulinux/export_symbol/mod2 modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "func1" [/usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.ko] undefined!
make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
[lingyun@localhost mod2]$


[lingyun@localhost mod2]$ sudo insmod mod2.ko
insmod: error inserting 'mod2.ko': -1 Unknown symbol in module
[lingyun@localhost mod2]$


解決上面的問題如下:

解決辦法是把mod_a的Module.symvers放到mod_b的當前路徑,從而編譯mod_b,符號信息會自動連接進去.
或者在mod_b的makefile中使用KBUILD_EXTRA_SYMBOLS指定mod_a的Module.symvers, 如:
KBUILD_EXTRA_SYMBOLS=/mod_a/Module.symvers

編譯mod_b時,搜索Module.symvers的路徑是:
1, kernel source path, e.g. /usr/src/kernels/linux-2.6.28.10
2, makefile中M=所指定的路徑, 它等效於變量KBUILD_EXTMOD的值
3, 變量KBUILD_EXTRA_SYMBOLS的值


此時Makefile文件如下:


[cpp]
obj-m:=mod2.o 
mod2-y:=mod_b.o 
 
<SPAN style="COLOR: #ff0000">KBUILD_EXTRA_SYMBOLS=~/fulinux/export_symbol/mod1/Module.symvers</SPAN> 
KERNELDIR := /lib/modules/$(shell uname -r)/build 
 
PWD:=$(shell pwd) 
 
modules: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
 
modules_install: 
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 
clean: 
    rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET) 

obj-m:=mod2.o
mod2-y:=mod_b.o

KBUILD_EXTRA_SYMBOLS=~/fulinux/export_symbol/mod1/Module.symvers
KERNELDIR := /lib/modules/$(shell uname -r)/build

PWD:=$(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
    rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET)

在編譯加載如下:

[lingyun@localhost mod2]$ make
make -C /lib/modules/2.6.32-279.el6.x86_64/build  M=/usr/local/src/lingyun/fulinux/export_symbol/mod2 modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
  CC [M]  /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod_b.o
  LD [M]  /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.mod.o
  LD [M]  /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.ko.unsigned
  NO SIGN [M] /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
[lingyun@localhost mod2]$ sudo insmod mod2.ko
[lingyun@localhost mod2]$


[lingyun@localhost mod2]$ dmesg | grep "In Func:"
In Func: func1...
In Func: func2...


可見模塊二調用模塊一的func1成功!!!

 

 

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved