[fw]谈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
[fw]谈EXPORT_SYMBOL使用的更多相关文章
- 谈EXPORT_SYMBOL使用
EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的.2.6就必须用EXPO ...
- [置顶]
谈EXPORT_SYMBOL使用
转自:http://blog.csdn.net/macrossdzh/article/details/4601648 EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static ...
- fw: 专访许鹏:谈C程序员修养及大型项目源码阅读与学习
C家最近也有一篇关于如何阅读大型c项目源代码的文章,学习..融合.. -------------------- ref:http://www.csdn.net/article/2014-06-05 ...
- 浅谈分词算法(5)基于字的分词方法(bi-LSTM)
目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 从I/O复用谈epoll为什么高效
上一篇文章中,谈了一些网络编程的基本概念.在现实使用中,用的最多的就是I/O复用了,无非就是select,poll,epoll 很多人提到网络就说epoll,认为epoll效率是最高的.单纯的这么认为 ...
- 浅谈我对DDD领域驱动设计的理解
从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...
- 谈一下关于CQRS架构如何实现高性能
CQRS架构简介 前不久,看到博客园一位园友写了一篇文章,其中的观点是,要想高性能,需要尽量:避开网络开销(IO),避开海量数据,避开资源争夺.对于这3点,我觉得很有道理.所以也想谈一下,CQRS架构 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
随机推荐
- harbar仓库的接口测试
一.接口测试命令 api接口文档:https://github.com/goharbor/harbor/blob/release-1.7.0/docs/swagger.yaml 1)查看所属项目的信息 ...
- 用css画一个倒三角
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 一、C#获取特性(坑)
一.C#获取特性(坑) [Description("系统状态码")] [Display(Name = "成功", Description = "请求成 ...
- 抽象类(abstract)与接口(interface)的区别
如果一个类中包含抽象方法,那么这个类就是抽象类.abstract只能用来修饰类或者方法,不能用来修饰属性. 接口是指一个方法的集合,接口中的所有方法都没有方法体.接口通过关键字interface实现. ...
- Linux系统理解以及Linux系统学习心得
原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 作者:严哲璟 说一下我对Lin ...
- kotlin中实现匿名内部类
1.常规的方式实现匿名内部类 valueAnimator.addUpdateListener(object :AnimatorUpdateListener { override fun onAnima ...
- CQOI2007 余数之和
Time Limit: 5 Sec Memory Limit: 128 MB Description 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + ...
- python wxpython
pip install wxpython import wxapp = wx.App(False)frame = wx.Frame(None, wx.ID_ANY, "Hollo World ...
- nyoj 253:LK的旅行 【旋转卡壳入门】
题目链接 求平面最大点对. 找凸包 -> 根据凸包运用旋转卡壳算法求最大点对(套用kuang巨模板) 关于旋转卡壳算法 #include<bits/stdc++.h> using n ...
- HTML5浏览器
你可以学会如何使用旧的浏览器正确处理新的HTML5. HTML5 浏览器支持 HTML5 支持所有现代浏览器. 此外,所有的浏览器,旧的和新的,自动处理未被识别的元素作为内联元素. 因为这样,你可以& ...