谈EXPORT_SYMBOL使用
EXPORT_SYMBOL只出現(xiàn)在2.6內(nèi)核中,在2.4內(nèi)核默認的非static 函數(shù)和變量都會自動導入到kernel 空間的, 都不用EXPORT_SYMBOL() 做標記的。
2.6就必須用EXPORT_SYMBOL() 來導出來(因為2.6默認不到處所有的符號)。
1、EXPORT_SYMBOL的作用是什么?
EXPORT_SYMBOL標簽內(nèi)定義的函數(shù)或者符號對全部內(nèi)核代碼公開,不用修改內(nèi)核代碼就可以在您的內(nèi)核模塊中直接調(diào)用,即使用EXPORT_SYMBOL可以將一個函數(shù)以符號的方式導出給其他模塊使用。
這里要和System.map做一下對比:
System.map 中的是連接時的函數(shù)地址。連接完成以后,在2.6內(nèi)核運行過程中,是不知道哪個符號在哪個地址的。
EXPORT_SYMBOL 的符號, 是把這些符號和對應的地址保存起來,在內(nèi)核運行的過程中,可以找到這些符號對應的地址。而模塊在加載過程中,其本質(zhì)就是能動態(tài)連接到內(nèi)核,如果在模塊中引用了內(nèi)核或其它模塊的符號,就要EXPORT_SYMBOL這些符號,這樣才能找到對應的地址連接。
2、使用方法
?? 第一、在模塊函數(shù)定義之后使用EXPORT_SYMBOL(函數(shù)名)
?? 第二、在掉用該函數(shù)的模塊中使用extern對之聲明
?? 第三、首先加載定義該函數(shù)的模塊,再加載調(diào)用該函數(shù)的模塊
另外,在編譯調(diào)用某導出函數(shù)的模塊時,往往會有WARNING: "****" [**********] undefined!
使用dmesg命令后會看到相同的信息。開始我以為只要有這個錯誤就不能加載模塊,后來上網(wǎng)查了一下,發(fā)現(xiàn)這主要是因為在編譯連接的時候還沒有和內(nèi)核打交道,當然找不到symbol了,但是由于你生成的是一個內(nèi)核模塊,所以LD不提示error,而是給出一個warning,寄希望于在insmod的時候,內(nèi)核能夠把這個symbol連接上。
參考資料:
-------------------------------------------------------------
http://blog.chinaunix.net/u/12592/showart_461504.html
一個模塊mod1中定義一個函數(shù)func1;在另外一個模塊mod2中定義一個函數(shù)func2,func2調(diào)用func1。
在模塊mod1中,EXPORT_SYMBOL(func1);
在模塊mod2中,extern int func1();
就可以在mod2中調(diào)用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函數(shù)成功的調(diào)用了mod1中的func1函數(shù)。
注意:
在編譯mod2的時候,出現(xiàn)一個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'
這主要是因為在編譯連接的時候還沒有和內(nèi)核打交道,當然找不到symbol了,但是由于你生成的是一個內(nèi)核模塊,所以LD不提示error,而是給出一個warning,寄希望于在insmod的時候,內(nèi)核能夠把這個symbol連接上。
-----------------------------------------------------------
http://www.lslnet.com/linux/f/docs1/i46/big5316526.htm
?請教關(guān)於EXPORT_SYMBOL
在一個文件裡要用到別的文件中的函數(shù) 用extern不就可以了麼
為什麼還需要EXPORT_SYMBOL
謝謝
????
Re: 請教關(guān)於EXPORT_SYMBOL
EXPORT_SYMBOL是給模塊用的。
????
Re: 請教關(guān)於EXPORT_SYMBOL
我看好像只要函數(shù)不是聲明為static的
在System.map中也有並且和EXPORT_SYMBOL的函數(shù)一樣。
模塊也可以使用的吧
????
Re: 請教關(guān)於EXPORT_SYMBOL
System.map 中的是鏈接時的函數(shù)地址。 連接完成以後,在內(nèi)核運行過程中,是不知道哪個符號在那個地址的。而這個文件是給調(diào)試用的。其中的內(nèi)容,kernel並不知道 。
EXPORT_SYMBOL 的符號, 是把這些符號和對應的地址,保存起來,在內(nèi)核運行的過程中,可以找到這些符號對應的地址的。
而module在加載過程中,其本質(zhì)就是動態(tài)連接到內(nèi)核,如果在模塊中引用了內(nèi)核或其它模塊的符號,就要 EXPORT_SYMBOL 這些符號,這樣才能找到對應的地址連接呀。 要不沒法連接的。
????
Re: 請教關(guān)於EXPORT_SYMBOL
那個是2.4的, 2.4中只要全局的, 符號就算導出了; 2.6則必須顯式調(diào)用EXPORT_SYMBOL或其變體。
????
Re: 請教關(guān)於EXPORT_SYMBOL
內(nèi)核模塊加載的鏈接過程,不是一個普通的鏈接過程,是內(nèi)核自己做的一個特殊的過程,
因此,單純extern是不可以的,內(nèi)核強行要求用EXPORT_SYMBOL
-------------------------------------------------------------
http://hi.baidu.com/leal/blog/item/d3e1cafcb97c2dfdfd037fc2.html
System.map[1]是Linux內(nèi)核符號文件,維護有內(nèi)核函數(shù)名稱和非堆棧變量名稱與各自地址的對應關(guān)系。
若內(nèi)核函數(shù)或變量要被內(nèi)核模塊調(diào)用,則必須使用EXPORT_SYMBOL宏進行處理,作用之一是將該符號連接到二進制文件的各個 __ksymtab_xx_xx section(參看include/linux/module.h,使用GCC編譯器的__attribute__關(guān)鍵字實現(xiàn)[2])。內(nèi)核加載模塊時,會先確認該模塊調(diào)用的各內(nèi)核函數(shù)是否已export(參看__find_symbol() kernel/module.c)。
比如FC5缺省會給vanilla內(nèi)核打補丁,使其不再export sys_open符號,這一點可搜索該內(nèi)核對應的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是,如果函數(shù)的聲明沒有加static,那么我理解就應該是全局的阿,沒什么要用
EXPORT_SYMBOL()
好象是因為系統(tǒng)需要生成類似于C00021_PRINTK 一類的鏈接用的,因為系統(tǒng)的函數(shù)本身其實是有其前綴的
模塊是動態(tài)加載的,需要一個運行時存在的符號表,找到符號。而我們一般所說的符號表是供靜態(tài)連接時定位符號地址用的。EXPORT_SYMBOL宏的作用就是把靜態(tài)符號表中的符號和地址放到運行時的符號表中(在一個section中)供運行時尋找符號用。
看一下EXPORT_SYMBOL的定義就知道了。
-------------------------------------------------------------
http://www.unixresources.net/linux/clf/linuxK/archive/00/00/71/60/716080.html
driver/char/console.c 里面提供了 這個函數(shù):
/* 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 里面調(diào)用:
void pm_restore_console(void)
{
?if (TEST_ACTION_STATE(SUSPEND_NO_OUTPUT))
??return;
//?reset_terminal(suspend_console, 1);
?reset_terminal(TTY_MAJOR,1);
可是編譯內(nèi)核的時候, 最后, 就說 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
大家?guī)驮\斷一下。 -DEXPORT_SYMTAB 我也加了。 還是不行。
EXPORT_SYMBOL()
被export的符號,是用來給加載模塊時鏈接時用的, 編譯內(nèi)核自身時, 和export 應該是沒有關(guān)系的. 看是否包含了對應的頭文件, console.c是被編譯為模塊, 還是編譯到內(nèi)核? 如果是別編譯到內(nèi)核, 只要在ui.c?
里包含了定義reset_terminal的頭文件,應該是可以編譯出來的.
沒錯,一陣見血。
找到原因了,console.o 的編譯被我們自己的宏給包住了(我們自己改了一些東西), 結(jié)果 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 函數(shù)和變量都會自動導入到kernel 空間的, 都不用EXPORT_SYMBOL() 做標記的。
2.6就必須用EXPORT_SYMBOL() 來導出來(因為2.6默認不到處所有的符號)。
本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/macrossdzh/archive/2009/09/28/4601648.aspx
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的谈EXPORT_SYMBOL使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle与mysql的区别总结(一)
- 下一篇: spring 环境配置