免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1290 | 回复: 0
打印 上一主题 下一主题

Linux模块编程机制之hello kernel 2.。。。。。。。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-03-13 16:39 |只看该作者 |倒序浏览
Linux模块编程机制之hello kernel 2.。。。。。。。
















Section Headers:
  1.   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  2.   [ 0]                   NULL            00000000 000000 000000 00      0   0  0

  3.   [ 1] .note.gnu.build-i NOTE            00000000 000034 000024 00   A  0   0  4

  4.   [ 2] .text             PROGBITS        00000000 000058 00005c 00  AX  0   0  4

  5.   [ 3] .rel.text         REL             00000000 01106c 000070 08     29   2  4

  6.   [ 4] .rodata.str1.1    PROGBITS        00000000 0000b4 000051 01 AMS  0   0  1

  7.   [ 5] .modinfo          PROGBITS        00000000 000108 0000c4 00   A  0   0  4

  8.   [ 6] __mcount_loc      PROGBITS        00000000 0001cc 000008 00   A  0   0  4

  9.   [ 7] .rel__mcount_loc  REL             00000000 0110dc 000010 08     29   6  4

  10.   [ 8] .data             PROGBITS        00000000 0001d4 000000 00  WA  0   0  4

  11.   [ 9] .gnu.linkonce.thi PROGBITS        00000000 0001d4 000164 00  WA  0   0  4

  12.   [10] .rel.gnu.linkonce REL             00000000 0110ec 000010 08     29   9  4

  13.   [11] .bss              NOBITS          00000000 000338 000000 00  WA  0   0  4

  14.   [12] .note.GNU-stack   PROGBITS        00000000 000338 000000 00   X  0   0  1

  15.   [13] .comment          PROGBITS        00000000 000338 00005a 00      0   0  1

  16.   [14] .debug_aranges    PROGBITS        00000000 000392 000020 00      0   0  1

  17.   [15] .rel.debug_arange REL             00000000 0110fc 000010 08     29  14  4

  18.   [16] .debug_pubnames   PROGBITS        00000000 0003b2 00006a 00      0   0  1

  19.   [17] .rel.debug_pubnam REL             00000000 01110c 000010 08     29  16  4

  20.   [18] .debug_info       PROGBITS        00000000 00041c 0090fe 00      0   0  1

  21.   [19] .rel.debug_info   REL             00000000 01111c 0043d0 08     29  18  4

  22.   [20] .debug_abbrev     PROGBITS        00000000 00951a 000550 00      0   0  1

  23.   [21] .debug_line       PROGBITS        00000000 009a6a 000858 00      0   0  1

  24.   [22] .rel.debug_line   REL             00000000 0154ec 000008 08     29  21  4

  25.   [23] .debug_frame      PROGBITS        00000000 00a2c4 000084 00      0   0  4

  26.   [24] .rel.debug_frame  REL             00000000 0154f4 000020 08     29  23  4

  27.   [25] .debug_str        PROGBITS        00000000 00a348 005507 01  MS  0   0  1

  28.   [26] .debug_pubtypes   PROGBITS        00000000 00f84f 00121c 00      0   0  1

  29.   [27] .rel.debug_pubtyp REL             00000000 015514 000010 08     29  26  4

  30.   [28] .shstrtab         STRTAB          00000000 010a6b 000128 00      0   0  1

  31.   [29] .symtab           SYMTAB          00000000 015524 000240 10     30  30  4

  32.   [30] .strtab           STRTAB          00000000 015764 0000e1 00      0   0  1
复制代码
Key to Flags:
  1.   W (write), A (alloc), X (execute), M (merge), S (strings)

  2.   I (info), L (link order), G (group), x (unknown)

  3.   O (extra OS processing required) o (OS specific), p (processor specific)
复制代码
模块使用ELF二进制文件结构,模块中包含了几个额外的段,普通的程序或库中不会出现。

__ksymtab段包含一个符号表,包括了模块导出的所有符号,该段中导出的符号可以由内核的所遇部分使用(不考虑许可证)。另外还有__ksymtab_gpl、__ksymtab_gpl_future和其命名意思相同。



       上面的.modinfo存储了在加载当前模块之前,内核中必须线性加载的所有其他模块名称,换句话说,该特定模块依赖的所有模块名称。



        .gun.linkonce.this_module提供了sruct module的一个实例,其中存储了模块的名称和指向二进制文件中的初始化函数和清理函数的指针。根据本段,内核即可判断特定的二进制文件是否为模块。如果没有该段,则拒绝装载文件。

      还有其他的段在上面的hello模块中没有出现,暂时不做分析了。



生成模块需要执行3个步骤:

1)  首先,模块源代码中的所有C文件都编译为普通话的.o目标文件。

2)  在为所有模块产生目标文件后,内核可以分析他们。找到的附加信息(例如,模块依赖关系)保存在一个独立的文件中,也编译为一个二进制文件。

3)  将前述两个步骤产生的二进制文件连接起来,生成最终的模块。



初始化和清理函数

       模块的初始化函数和清理函数,保存在.gun.linkonce.module段中的module实例中,该实例位于上述为每个模块自动生成的附加文件中。对上面的hello.c文件编译生成的hello.mod.c中:

[cpp] view plaincopyprint?
  1. struct module __this_module  
  2. __attribute__((section(".gnu.linkonce.this_module"))) = {  
  3. .name = KBUILD_MODNAME,  
  4. .init = init_module,  
  5. #ifdef CONFIG_MODULE_UNLOAD   
  6. .exit = cleanup_module,  
  7. #endif   
  8. .arch = MODULE_ARCH_INIT,  
  9. };  
  10.   
  11. static const char __module_depends[]  
  12. __used  
  13. __attribute__((section(".modinfo"))) =  
  14. "depends=";  
  15. struct module __this_module
  16. __attribute__((section(".gnu.linkonce.this_module"))) = {
  17. .name = KBUILD_MODNAME,
  18. .init = init_module,
  19. #ifdef CONFIG_MODULE_UNLOAD
  20. .exit = cleanup_module,
  21. #endif
  22. .arch = MODULE_ARCH_INIT,
  23. };

  24. static const char __module_depends[]
  25. __used
  26. __attribute__((section(".modinfo"))) =
  27. "depends=";
复制代码
KBUILD_MODNAME包含了模块的名称,只有将代码编译为模块时才定义

导出符号

        内核为导出符号提供了两个宏:EXPORT_SYMBOL和EXPORT_SYMBOL_GPL。在我们的hello_h.c中用到了EXPORT_SYMBOL,我们看看内核是怎么定义的。在<module.h>中

[cpp] view plaincopyprint?
  1. /* Mark the CRC weak since genksyms apparently decides not to
  2. * generate a checksums for some symbols */  
  3. #define __CRC_SYMBOL(sym, sec)                  \   
  4.     extern void *__crc_##sym __attribute__((weak));     \  
  5.     static const unsigned long __kcrctab_##sym      \  
  6.     __used                          \  
  7.     __attribute__((section("__kcrctab" sec), unused))   \  
  8.     = (unsigned long) &__crc_##sym;  
  9. #else   
  10. #define __CRC_SYMBOL(sym, sec)   
  11. #endif   
  12.   
  13. /* For every exported symbol, place a struct in the __ksymtab section */  
  14. #define __EXPORT_SYMBOL(sym, sec)               \   
  15.     extern typeof(sym) sym;                 \  
  16.     __CRC_SYMBOL(sym, sec)                  \  
  17.     static const char __kstrtab_##sym[]         \  
  18.     __attribute__((section("__ksymtab_strings"), aligned(1))) \  
  19.     = MODULE_SYMBOL_PREFIX #sym;                        \  
  20.     static const struct kernel_symbol __ksymtab_##sym   \  
  21.     __used                          \  
  22.     __attribute__((section("__ksymtab" sec), unused))   \  
  23.     = { (unsigned long)&sym, __kstrtab_##sym }  
  24.   
  25. #define EXPORT_SYMBOL(sym)                  \   
  26.     __EXPORT_SYMBOL(sym, "")  
  27.   
  28. #define EXPORT_SYMBOL_GPL(sym)                  \   
  29.     __EXPORT_SYMBOL(sym, "_gpl")  
  30.   
  31. #define EXPORT_SYMBOL_GPL_FUTURE(sym)               \   
  32.     __EXPORT_SYMBOL(sym, "_gpl_future")  
  33. /* Mark the CRC weak since genksyms apparently decides not to
  34. * generate a checksums for some symbols */
  35. #define __CRC_SYMBOL(sym, sec)                                        \
  36.         extern void *__crc_##sym __attribute__((weak));                \
  37.         static const unsigned long __kcrctab_##sym                \
  38.         __used                                                        \
  39.         __attribute__((section("__kcrctab" sec), unused))        \
  40.         = (unsigned long) &__crc_##sym;
  41. #else
  42. #define __CRC_SYMBOL(sym, sec)
  43. #endif

  44. /* For every exported symbol, place a struct in the __ksymtab section */
  45. #define __EXPORT_SYMBOL(sym, sec)                                \
  46.         extern typeof(sym) sym;                                        \
  47.         __CRC_SYMBOL(sym, sec)                                        \
  48.         static const char __kstrtab_##sym[]                        \
  49.         __attribute__((section("__ksymtab_strings"), aligned(1))) \
  50.         = MODULE_SYMBOL_PREFIX #sym;                            \
  51.         static const struct kernel_symbol __ksymtab_##sym        \
  52.         __used                                                        \
  53.         __attribute__((section("__ksymtab" sec), unused))        \
  54.         = { (unsigned long)&sym, __kstrtab_##sym }

  55. #define EXPORT_SYMBOL(sym)                                        \
  56.         __EXPORT_SYMBOL(sym, "")

  57. #define EXPORT_SYMBOL_GPL(sym)                                        \
  58.         __EXPORT_SYMBOL(sym, "_gpl")

  59. #define EXPORT_SYMBOL_GPL_FUTURE(sym)                                \
  60.         __EXPORT_SYMBOL(sym, "_gpl_future")
复制代码
对每个导出的符号生成了两段代码。其用途:

.__kstrtab_function是一个静态变量,保存在__ksymtab_strings段中。他是一个字符串,其值对应于函数的名称。

.__ksymtab段中存储了一个kernel_symbol实例。它包括两个指针,一个指向导出的函数,另一个指向在字符串表中刚建立的项。

这些使得内核根据函数字符串名称,即可找到匹配的代码地址。

在对导出函数启用内核版本控制特性时,会使用__CRC_SYMBOL;



版本控制信息

       .modinfo段中总是会存储某些必不可少的版本控制信息,无论内核的版本控制特性是否启用。这使得可以从各种内核配置中区分出特别印象整个内核源代码的那些配置,这些可能需要一个单独的模块集合。我们看上面hello模块生成的hello.mod.c文件中的

[cpp] view plaincopyprint?
MODULE_INFO(vermagic, VERMAGIC_STRING);  
MODULE_INFO(vermagic, VERMAGIC_STRING);
VERMAGIC_STRING是一个字符串,表示内核配置的关键特性,在内核源码中定义为:

[cpp] view plaincopyprint?
  1. #define VERMAGIC_STRING                         \   
  2.     UTS_RELEASE " "                         \  
  3.     MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT             \  
  4.     MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS   \  
  5.     MODULE_ARCH_VERMAGIC  
  6. #define VERMAGIC_STRING                                                 \
  7.         UTS_RELEASE " "                                                        \
  8.         MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                         \
  9.         MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS        \
  10.         MODULE_ARCH_VERMAGIC
复制代码
内核自身和每个模块中都会存储VERMAGIC_STRING的一份副本。只有内核与模块存储的两个字符串匹配时,模块才能加载。这意味模块和内核的相关配置必须是一致的。内核版本也会存储,但在比较时会忽略。内核版本不同的模块,只要剩余的版本字符串匹配,仍然可以装载。

模块的插入和卸载

       模块的装载和卸载在内核中用两个系统调用实现:sys_init_module和sys_delete_module,定义在<kernel/module.c>中两个函数的实现比较复杂,有兴趣可以看看。

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP