談EXPORT_SYMBOL使用

 

Makefile 裏添加:

KBUILD_EXTRA_SYMBOLS += /home/peng/omapl138/module/a/Module.symvers

export KBUILD_EXTRA_SYMBOLS

否則出現unknow symbol . version等錯誤

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

 

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

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/macrossdzh/archive/2009/09/28/4601648.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章