转自:http://blog.csdn.net/macrossdzh/article/details/4601648

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默认不到处所有的符号)。

[置顶] 谈EXPORT_SYMBOL使用的更多相关文章

  1. 在UWP中页面滑动导航栏置顶

    最近在研究掌上英雄联盟,主要是用来给自己看新闻,顺便copy个界面改一下段位装装逼,可是在我copy的时候发现这个东西 当你滑动到一定距离的时候导航栏会置顶不动,这个特性在微博和淘宝都有,我看了@ms ...

  2. WinFrom窗体始终置顶

    调用WindowsAPI使窗体始终保持置顶效果,不被其他窗体遮盖: [DllImport("user32.dll", CharSet = CharSet.Auto)] privat ...

  3. winform窗体置顶

    winform窗体置顶 金刚 winform 置顶 今天做了一个winform小工具.需要设置置顶功能. 网上找了下,发现百度真的很垃圾... 还是必应靠谱些. 找到一个可以链接. https://s ...

  4. 自定义置顶TOP按钮

    简述一下,分为三个步骤: 1. 添加Html代码 2. 调整Css样式 3. 添加Jquery代码 具体代码如下: <style type="text/css"> #G ...

  5. ahk之路:利用ahk在window7下实现窗口置顶

    操作系统:win7 64位 ahk版本:autohotkey_L1.1.24.03 今天安装了AutoHotkey_1.1.24.03.SciTE.PuloversMacroCreator,重新开始我 ...

  6. Qt中让Qwidget置顶的方法

    一般来是说窗体置顶和取消只要        setWindowFlags(Qt::WindowStaysOnTopHint);        setWindowFlags(Qt::Widget); 要 ...

  7. js之滚动置顶效果

    0.js获取高度 ? 1 2 3 4 5 6 document.all   // 只有ie认识   document.body.clientHeight              // 文档的高,屏幕 ...

  8. Javascript笔记----实现Page页面右下角置顶按钮.

    从用博客开始,发现博客园中很多博友的博客中在Page右下角都有个图标,不论屏幕怎么拉伸,都始终停留在右下角.点击后页面置顶.后面想想写一个Demo来实现这种效果吧. 一. 图标右下角固定. 1.SS ...

  9. JavaScript学习笔记-元素在滚动条滑动一定高度后自动置顶

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

随机推荐

  1. Web框架Django(一)

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...

  2. pjblog支持QQ、新浪微博一键登录

    转载地址: http://www.ruisoftcn.com/blog/article.asp?id=955

  3. 【BZOJ3505】[Cqoi2014]数三角形 组合数

    [BZOJ3505][Cqoi2014]数三角形 Description 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个.下图为4x4的网格上的一个三角形. 注意三角形的三点不能共线. ...

  4. 【BZOJ1110】[POI2007]砝码Odw 贪心

    [BZOJ1110][POI2007]砝码Odw Description 在byteotian公司搬家的时候,他们发现他们的大量的精密砝码的搬运是一件恼人的工作.公司有一些固定容量的容器可以装这些砝码 ...

  5. IE浏览器 get请求缓存问题

    场景: 比较简单是使用的SpringMVC框架,在做资源国际化的时候,遇到了这个问题.具体做的操作是在页面上点击切换语言的时候,需要发起请求在Controller中切换Locale. 问题: 1.开始 ...

  6. Struts2中的数据类型转换

    Struts2对数据的类型转换 一.Struts2中自带类型转换拦截器 Struts2内部提供了大量转换器,用来完成数据类型转换的问题,有如下 * boolean 和 Boolean * char和 ...

  7. asp.net mvc4 之Webapi之应用客户端访问服务器端

    一.说明 客户端项目类型设计为:winform(winform窗体项目类型) 服务器端项目类型设计为:asp.net mvc4  webapi 在这里分为项目运行和调试两种情况讨论: 运行: 这种情况 ...

  8. Rethinking the Inception Architecture for Computer Vision

    https://arxiv.org/abs/1512.00567 Convolutional networks are at the core of most state-of-the-art com ...

  9. tomcat安装后问题解决

      tomcat安装后问题解决 (1)tomcat无法正常启动的原因分析 JAVA_HOME 配置错误,或者没有配置 如果你的机器已经占有了8080 端口,则无法启动, 解决方法 (1) 你可以808 ...

  10. Riak Core Guide 2

    Learn Riak Core Step By Step 2 Riak Core, The Coordinator What is a Coordinator? 顾名思义. Coordinator即使 ...