zoukankan      html  css  js  c++  java
  • 谈EXPORT_SYMBOL使用

    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连接上。

    参考资料:

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

    http://blog.chinaunix.net/u/12592/showart_461504.html

    一个模块mod1中定义一个函数func1;在另外一个模块mod2中定义一个函数func2,func2调用func1。
    在模块mod1中,EXPORT_SYMBOL(func1);
    在模块mod2中,extern int func1();
    就可以在mod2中调用func1了。

    参考:
    http://topic.csdn.net/u/20070910/09/ee2cff13-9179-41e3-9292-4fd73261f709.html
    http://www.dev-archive.com/msdn-archive/524/kernel-driver-5244619.shtm

    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:
    root@wangyao-desktop:~/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连接上。

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

    http://www.lslnet.com/linux/f/docs1/i46/big5316526.htm

     請教關於EXPORT_SYMBOL

    在一個文件裡要用到別的文件中的函數 用extern不就可以了麼

    為什麼還需要EXPORT_SYMBOL

    謝謝

        
    Re: 請教關於EXPORT_SYMBOL

    EXPORT_SYMBOL是給模塊用的。


        
    Re: 請教關於EXPORT_SYMBOL

    我看好像只要函數不是聲明為static的
    在System.map中也有並且和EXPORT_SYMBOL的函數一樣。

    模塊也可以使用的吧

        
    Re: 請教關於EXPORT_SYMBOL

    System.map 中的是鏈接時的函數地址。 連接完成以後,在內核運行過程中,是不知道哪個符號在那個地址的。而這個文件是給調試用的。其中的內容,kernel並不知道 。


    EXPORT_SYMBOL 的符號, 是把這些符號和對應的地址,保存起來,在內核運行的過程中,可以找到這些符號對應的地址的。

    而module在加載過程中,其本質就是動態連接到內核,如果在模塊中引用了內核或其它模塊的符號,就要 EXPORT_SYMBOL 這些符號,這樣才能找到對應的地址連接呀。 要不沒法連接的

        
    Re: 請教關於EXPORT_SYMBOL

    那個是2.4的, 2.4中只要全局的, 符號就算導出了; 2.6則必須顯式調用EXPORT_SYMBOL或其變體。

        
    Re: 請教關於EXPORT_SYMBOL

    內核模塊加載的鏈接過程,不是一個普通的鏈接過程,是內核自己做的一個特殊的過程,
    因此,單純extern是不可以的,內核強行要求用EXPORT_SYMBOL

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

    http://hi.baidu.com/leal/blog/item/d3e1cafcb97c2dfdfd037fc2.html

    System.map[1]是Linux内核符号文件,维护有内核函数名称和非堆栈变量名称与各自地址的对应关系。

    若内核函数或变量要被内核模块调用,则必须使用EXPORT_SYMBOL宏进行处理,作用之一是将该符号连接到二进制文件的各个 __ksymtab_xx_xx section(参看include/linux/module.h,使用GCC编译器的__attribute__关键字实现[2])。内核加载模块 时,会先确认该模块调用的各内核函数是否已export(参看__find_symbol() kernel/module.c)。

    比如FC5缺省会给vanilla内核打补丁,使其不再export sys_open符号,这一点可搜索该内核对应的System.map文件进行确认,看是否存在__ksymtab_sys_open符号。

    [1] The system.map File
    http://www.dirac.org/linux/system.map/

    [2] Using GNU C __attribute__
    http://www.unixwiz.net/techtips/gnu-c-attributes.html

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

    http://www.linuxsir.org/bbs/thread347677.html

    在编写module是,如果函数的声明没有加static,那么我理解就应该是全局的阿,没什么要用
    EXPORT_SYMBOL()

    好象是因为系统需要生成类似于C00021_PRINTK 一类的链接用的,因为系统的函数本身其实是有其前缀的

    模块是动态加载的,需要一个运行时存在的符号表,找到符号。而我们一般所说的符号表是供静态连接时定位符号地址用的。EXPORT_SYMBOL宏的作用就是把静态符号表中的符号和地址放到运行时的符号表中(在一个section中)供运行时寻找符号用
    看一下EXPORT_SYMBOL的定义就知道了。

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

    http://www.unixresources.net/linux/clf/linuxK/archive/00/00/71/60/716080.html

    driver/char/console.c 里面提供了 这个函数: 

    /* console_sem is held (except via vc_init()) */

    void reset_terminal(int currcons, int do_clear)

    {

    top = 0;

    bottom = video_num_lines;

    。。。。。。



    在console.c 的最后面也有: 

    /* 
    * Visible symbols for modules 
    */ 

    EXPORT_SYMBOL(fg_console); 
    EXPORT_SYMBOL(console_blank_hook); 
    EXPORT_SYMBOL(hide_cursor); 
    EXPORT_SYMBOL(reset_terminal); //这个 


    drivers/char/Makefile 里面也有: 


    # All of the (potential) objects that export symbols.

    # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.



    export-objs := busmouse.o console.o keyboard.o sysrq.o

    misc.o pty.o random.o selection.o serial.o

    sonypi.o tty_io.o tty_ioctl.o generic_serial.o

    au1000_gpio.o hp_psaux.o nvram.o scx200.o



    我要在kernel/power/ui.c 里面调用: 


    void pm_restore_console(void)

    {



    if (TEST_ACTION_STATE(SUSPEND_NO_OUTPUT))

    return;



    // reset_terminal(suspend_console, 1);

    reset_terminal(TTY_MAJOR,1);






    可是编译内核的时候, 最后, 就说 undefined reset_terminal () , 奇怪了。 


    /usr/bin/mips-linux-ld -G 0 -static -T arch/mips/ld.script arch/mips/kernel/head.o 
    arch/mips/kernel/init_task.o init/main.o init/version.o init/do_mounts.o --start-group 
    arch/mips/kernel/kernel.o arch/mips/mm/mm.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o 
    arch/mips/math-emu/fpu_emulator.o arch/mips/emma2_se/emma2.o drivers/char/char.o 
    drivers/block/block.o drivers/misc/misc.o drivers/net/net.o drivers/ide/idedriver.o 
    drivers/pci/driver.o drivers/mtd/mtdlink.o drivers/net/wireless/wireless_net.o 
    drivers/usb/usbdrv.o drivers/media/media.o drivers/md/mddev.o net/network.o 
    arch/mips/lib/lib.a /home/work/data3/standby/dv_kernel_suspend2/linux/lib/lib.a 
    --end-group -o vmlinux 
    kernel/kernel.o: In function `pm_restore_console': 
    kernel/kernel.o(.text+0x16030): undefined reference to `reset_terminal' 
    kernel/kernel.o(.text+0x16030): relocation truncated to fit: R_MIPS_26 reset_terminal 
    make[1]: *** [kallsyms] Error 1 
    make[1]: Leaving directory `/home/work/data3/standby/dv_kernel_suspend2/linux' 
    make: *** [vmlinux] Error 2 



    大家帮诊断一下。 -DEXPORT_SYMTAB 我也加了。 还是不行。

     

    EXPORT_SYMBOL()
    被export的符号,是用来给加载模块时链接时用的, 编译内核自身时, 和export 应该是没有关系的. 看是否包含了对应的头文件, console.c是被编译为模块, 还是编译到内核? 如果是别编译到内核, 只要在ui.c 
    里包含了定义reset_terminal的头文件,应该是可以编译出来的.

    没错,一阵见血。
    找到原因了,console.o 的编译被我们自己的宏给包住了(我们自己改了一些东西), 结果 console.o 没有被编译出来,当然就找不到reset_terminal() 了。
    所以光有:
    export-objs := busmouse.o console.o keyboard.o sysrq.o
    misc.o pty.o random.o selection.o serial.o
    sonypi.o tty_io.o tty_ioctl.o generic_serial.o
    au1000_gpio.o hp_psaux.o nvram.o scx200.o
    也是不行的,
    还有了一个 obj-y =+ console.o

    我补充一下:
    以前做2.4的时候确实如此,
    我记得是 对于2.4 来说, 默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。

    2.6就必须用EXPORT_SYMBOL() 来导出来(因为2.6默认不到处所有的符号)。

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

    http://forum.kernelnewbies.org/read.php?12,153

  • 相关阅读:
    每日总结2021.9.14
    jar包下载mvn
    每日总结EL表达语言 JSTL标签
    每日学习总结之数据中台概述
    Server Tomcat v9.0 Server at localhost failed to start
    Server Tomcat v9.0 Server at localhost failed to start(2)
    链表 java
    MVC 中用JS跳转窗体Window.Location.href
    Oracle 关键字
    MVC 配置路由 反复走控制其中的action (int?)
  • 原文地址:https://www.cnblogs.com/Ph-one/p/6124986.html
Copyright © 2011-2022 走看看