driver: linux2.6 内核模块导出函数实例(EXPORT_SYMBOL)

转载 2015年07月11日 10:44:46

内核版本:2.6.38-11-generic

    内核自己都大量利用内核符号表导出函数,那么应该导出呢,ldd3上面说只需要EXPORT_SYMBOL一类的宏导出即可,结果试了很久都不行,最后查看文档,算是明白一点了。

    对于导出符号表,内核文档给出了三种解决方案,见尾部,现在忽略。

    现在有两个模块,a模块导出函数myprint,b模块使用该函数,想象一下如果a模块 EXPORT_SYMBOL(myprint) ,实际上b模块知道吗,很明显b模块对这件事情不是很清楚(这么说不是很准确),要调用a模块的myprint函数,需要知道myprint函数在内存中的位置,首先在内核符号表中是没有说明的,所以...

    当我们编译完a模块后,看看有些什么文件,是不是有一个Module.symvers文件,打开看看什么状况?
0x705034f7    myprint    /home/darren/Desktop/darren/print/myprint    EXPORT_SYMBOL
好了,这一行对b模块来说已经足够了,指定了内存位置,符号名称,模块路径。最简单的方法就是把这个文件复制到b模块所在目录,然后编译就没有讨厌的错误了,可以正常insmod模块。这种方法是内核文档中提到的方法之一。

    但是每次调用该函数都要复制一次,更糟糕的是a模块每编译一次,都要重新复制一次,为什么内核自己导出的函数我们可以直接用呢?现在就就解决:

    编译内核的时候同样会生成一个Module.symvers文件,内核导出的所有符号都在里面,我们在编译模块的时候实际上会调用内核的顶层makefile,也就是说内核的Module.symvers对我们的模块是可见的,和我们自己的Module.symvers文件一样,OK,把a模块的Module.symvers文件合并到内核的Module.symvers文件中,这时候myprint函数就成了真正的导出函数了,其他的模块只需要生命一下就可以用了。

代码如下
a模块代码

点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/kernel.h> 

  4. MODULE_LICENSE("GPL");
  5. int myprint(void)
  6. {
  7.     printk("c");
  8.     return 0;
  9. }
  10. static int darren_init(void)
  11. {
  12.     return 0;
  13. }
  14. static void darren_exit(void)
  15. {
  16. }
  17. module_init(darren_init);
  18. module_exit(darren_exit);
  19. EXPORT_SYMBOL(myprint);
b模块代码

点击(此处)折叠或打开

  1. #include <linux/seq_file.h>
  2. #include <linux/cdev.h>
  3. #include <asm/system.h> 

  4. MODULE_LICENSE("GPL");
  5. extern int print(void);
  6. static int darren_init(void)
  7. {
  8.     int i=0;
  9.     printk("b module init\n");
  10.     for(;i<10;i++)print();
  11.     return 0;
  12. }
  13. static void darren_exit(void)
  14. {
  15. }
  16. module_init(darren_init);
  17. module_exit(darren_exit);
a模块的Makefile如下:
点击(此处)折叠或打开
  1. NAME:=a
  2. SYM:=/usr/src/linux-headers-2.6.38-8-generic/Module.symvers
  3. DIR:=/lib/modules/$(shell uname -r)/build/
  4. PWD:=$(shell pwd)
  5. obj-= $(NAME).o
  6. build: 
  7.     
  8.     make -C $(DIR) M=$(PWD)
  9.     sudo chmod 777 $(SYM)
  10.     sudo sed -'/myprint/d' $(SYM)
  11.     sudo cat Module.symvers>>$(SYM)
  12.     sudo chmod 644 $(SYM)

b模块的makefile:
点击(此处)折叠或打开
  1. NAME:=b
  2. DIR:=/lib/modules/$(shell uname -r)/build/
  3. PWD:=$(shell pwd)
  4. obj-= $(NAME).o
  5. build: 
  6.     make -C $(DIR) M=$(PWD)

注意:路径/usr/src/linux-headers-2.6.38-8-generic/Module.symvers 有可能不对如果不行就改成/usr/src/linux-headers-`uname -r`-generic/Module.symvers

内核文档:

点击(此处)折叠或打开

  1. Sometimes, an external module uses exported symbols from
  2.     another external module. kbuild needs to have full knowledge of
  3.     all symbols to avoid spitting out warnings about undefined
  4.     symbols. Three solutions exist for this situation.

  5.     NOTE: The method with a top-level kbuild file is recommended
  6.     but may be impractical in certain situations.

  7.     Use a top-level kbuild file
  8.         If you have two modules, foo.ko and bar.ko, where
  9.         foo.ko needs symbols from bar.ko, you can use a
  10.         common top-level kbuild file so both modules are
  11.         compiled in the same build. Consider the following
  12.         directory layout:

  13.         ./foo/ <= contains foo.ko
  14.         ./bar/ <= contains bar.ko

  15.         The top-level kbuild file would then look like:

  16.         #./Kbuild (or ./Makefile):
  17.             obj-:= foo/ bar/

  18.         And executing

  19.             $ make -C $KDIR M=$PWD

  20.         will then do the expected and compile both modules with
  21.         full knowledge of symbols from either module.

  22.     Use an extra Module.symvers file
  23.         When an external module is built, a Module.symvers file
  24.         is generated containing all exported symbols which are
  25.         not defined in the kernel. To get access to symbols
  26.         from bar.ko, copy the Module.symvers file from the
  27.         compilation of bar.ko to the directory where foo.ko is
  28.         built. During the module build, kbuild will read the
  29.         Module.symvers file in the directory of the external
  30.         module, and when the build is finished, a new
  31.         Module.symvers file is created containing the sum of
  32.         all symbols defined and not part of the kernel.

  33.     Use "make" variable KBUILD_EXTRA_SYMBOLS
  34.         If it is impractical to copy Module.symvers from
  35.         another module, you can assign a space separated list
  36.         of files to KBUILD_EXTRA_SYMBOLS in your build file.
  37.         These files will be loaded by modpost during the
  38.         initialization of its symbol tables.

driver: linux2.6 内核模块导出函数实例(EXPORT_SYMBOL)

内核版本:2.6.38-11-generic     内核自己都大量利用内核符号表导出函数,那么应该导出呢,ldd3上面说只需要EXPORT_SYMBOL一类的宏导出即可,结果试了很久都不行,最...
  • daydring
  • daydring
  • 2014年05月20日 11:12
  • 454

基于 linux 2.6 内核的内核模块编写

       最近对LInux驱动程序有点感兴趣,找了本LINUX DEVICE DRVERS,读了前面的内核概述,就在机子上试了试书中的Hello World的程序。结果编译失败,才发现这本书有点老...
  • soulxu
  • soulxu
  • 2007年11月20日 22:23
  • 1558

Linux开发心得总结20 - 内核编程中的全局变量使用(EXPORT_SYMBOL())

和我们通常写程序不同,如果仅仅是全局变量,虽然编译内核的时候能连接成功,但是连接之后再就没有办法使用这个变量了 而模块的加载是运行时的,它引用某个变量时,内核需要解析它,否则模块不能工作,EXPOR...
  • ynttmp
  • ynttmp
  • 2012年06月06日 09:45
  • 2674

Linux内核—EXPORT_SYMBOL宏的使用

前言 EXPORT_SYMBOL宏的使用时出现在Linux-2.6之后,在Linux-2.4内核中,默认的非static 函数和变量都会自动导入到kernel 空间, 都不用EXPORT_SYMBO...
  • zengxianyang
  • zengxianyang
  • 2016年01月30日 17:41
  • 4013

Linux驱动开发——EXPORT_SYMBOL的使用

编写C程序时,如果需要使用某个外部的函数,通常的做法是 #include 包含该函数原型(prototype)的头文件,然后在程序中进行调用。经过编译链接后,程序就能顺利调用该函数。但是对于内核模块来...
  • luckydarcy
  • luckydarcy
  • 2016年05月18日 03:46
  • 760

linux内核模块(2)导出符号

/*本文由真胖子同志私人定制,烦请转载保留来源*/ 内核模块不但可以使用内核和其他模块导出的符号,还可以向外部导出自己的符号。如果一个模块向外界导出符号,那么模块的编译工具链将负责生成这写导出符号的...
  • lileidajiangjun
  • lileidajiangjun
  • 2014年02月28日 20:38
  • 1373

linux2.6内核模块的编译

首先将下面的程序写进一个hello1.c的文件里:#vim hello1.c#include "linux/module.h"#include "linux/kernel.h"#include "li...
  • qq_16124631
  • qq_16124631
  • 2014年06月06日 20:30
  • 197

Linux2.6下内核模块编译

 Linux2.6下内核模块编译经过几天的努力,自己写的内核模块终于可以在linux2.6下编译并加载道内核中了,现在对这几天的努力做个总结。在旧的版本下(如linux 2.4)linux内核模块的编...
  • nmzrl
  • nmzrl
  • 2007年04月06日 17:07
  • 1410

Linux中EXPORT_SYMBOL的用法(附:自己的应用)

EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。您还...
  • haitang_han
  • haitang_han
  • 2011年06月08日 13:21
  • 770

Kernel-----EXPORT_SYMBOL使用

EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动 导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的。 2.6就必须用...
  • yf210yf
  • yf210yf
  • 2013年07月28日 13:48
  • 5683
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:driver: linux2.6 内核模块导出函数实例(EXPORT_SYMBOL)
举报原因:
原因补充:

(最多只允许输入30个字)