Chinaunix首页 | 论坛 | 博客
  • 博客访问: 167325
  • 博文数量: 18
  • 博客积分: 285
  • 博客等级: 二等列兵
  • 技术积分: 201
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-02 11:26
文章分类

全部博文(18)

文章存档

2015年(2)

2014年(4)

2012年(12)

我的朋友

分类: LINUX

2012-11-21 17:37:40

构造和运行模块
(一)Hello World 模块

点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. MODULE_LICENSE("Dual BSD/GPL");

  4. static int hello_init(void)
  5. {
  6.     printk(KERN_ALERT "Hello, world\n");
  7.     return 0;
  8. }

  9. static void hello_exit(void)
  10. {
  11.     printk(KERN_ALERT "Goodbye, cruel world\n");
  12. }

  13. module_init(hello_init);
  14. module_exit(hello_exit);
此段代码来自ldd3的例子,由于之前稍微接触过驱动模块等相关皮毛知识,我看到这段代码产生了疑问:初始化和卸载函数怎么没有被 __init,__exit 修饰,书中提到:
__init是一种暗示,它表明该函数仅在初始化时被使用,模块装载完毕后,它会被扔到,将模块初始化函数所占的内存释放出来,以便把无用的代码所占的内存腾出来给其它模块使用。
那么这个 __init是个什么东西?在 /include/linux/init.h 中就有它的定义:

  1. #define __init     __section(.init.text) __cold notrace
后面的 _cold notrace,是gcc编译相关的一些扩展宏,具体什么作用没仔细看,但是经过展开, __init会变成:

  1. #define __init __attribute__ ((__section__ (".init.text")))
  __attribute__ 也是GNU C的扩展,它主要设置代码的一些属性,以便代码的优化,布局,安全等更好。单从字面上看 __section__ 就知道这是对代码布局属性进行设置,一段代码最基本的段有:代码的(.text),数据段(.data),BSS段(.bss)等。其他一些扩展的段加起来超过十多个,具体多少不知道。这里就有个 .init.text 从字面意思姑且叫做:初始化代码段。ldd3上说这段在执行完后会被释放,这个段在vmlinux.lds这个内核连接脚本里面声明。
除了__init还有__initdata,内核代码中,对这段有样的说明:


  1. /* These macros are used to mark some functions or
  2.  * initialized data (doesn't apply to uninitialized data)
  3.  * as `initialization' functions. The kernel can take this
  4.  * as hint that the function is used only during the initialization
  5.  * phase and free up used memory resources after
  6.  *
  7.  * Usage:
  8.  * For functions:
  9.  *
  10.  * You should add __init immediately before the function name, like:
  11.  *
  12.  * static void __init initme(int x, int y)
  13.  * {
  14.  * extern int z; z = x * y;
  15.  * }
  16.  *
  17.  * If the function has a prototype somewhere, you can also add
  18.  * __init between closing brace of the prototype and semicolon:
  19.  *
  20.  * extern int initialize_foobar_device(int, int, int) __init;
  21.  *
  22.  * For initialized data:
  23.  * You should insert __initdata between the variable name and equal
  24.  * sign followed by value, e.g.:
  25.  *
  26.  * static int init_variable __initdata = 0;
  27.  * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
  28.  *
  29.  * Don't forget to initialize data not at file scope, i.e. within a function,
  30.  * as gcc otherwise puts the data into the bss section and not into the init
  31.  * section.
  32.  *
  33.  * Also note, that this data cannot be "const".
  34.  */

  35. /* These are for everybody (although not all archs will actually
  36.    discard it in modules) */
需要注意的是:
如果一个函数的原型声明在别处,也可以用__init修饰:

  1. extern int initialize_foobar_device(int, int, int) __init;
       修饰数据用 __initdata,用法:

  1. * static int init_variable __initdata = 0;
  2.  * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
尤其注意的是一定要对这些数据初始化,并且要在函数外部,否则他们会被编译器扔到BSS段。还有就是不要用"const"修饰这类数据,这是显而易见的。
__exit,__exitdata用法同__init,__initdata类似,放于.exit.text段


对于更深的:http://blog.csdn.net/muge0913/article/details/7251326

       一般模块里面的函数都申明为 static ,既然它被称之为模块,那么要尽量让它们之间的关联性减小,static就是基于此的,当然这只是我的理解。


  1. module_init(hello_init);
  2. module_exit(hello_exit);
这2个函数是必须的,模块的入口和出口都是通过它引导的。这是2个宏:


  1. #define module_init(x)    __initcall(x);
  2. #define module_exit(x)    __exitcall(x);
  3. #define __define_initcall(level,fn,id) \
  4. static initcall_t __initcall_##fn##id __used \
  5. __attribute__((__section__(".initcall" level ".init"))) = fn
又是对段属性进行修改,我想肯定有相应的程序维护这些特殊地段。

虽然模块要尽量减小关联性,但是有时候不得已或者说很有必要很外部交流下,所以就有:


  1. #define EXPORT_SYMBOL(sym)                    \
  2.     __EXPORT_SYMBOL(sym, "")

  3. #define EXPORT_SYMBOL_GPL(sym)                    \
  4.     __EXPORT_SYMBOL(sym, "_gpl")

  5. #define EXPORT_SYMBOL_GPL_FUTURE(sym)                \
  6.     __EXPORT_SYMBOL(sym, "_gpl_future")
后面2个仅限对GPL下的模块,对他们深究,又是段属性:http://www.cnblogs.com/mywolrd/archive/2009/04/01/1930696.html
http://blog.sina.com.cn/s/blog_701142a40100m45h.html

之前一直以为只能对变量,貌似对函数也可以。

(二)模块参数
阅读(2097) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~