免费注册 查看新帖 |

Chinaunix

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

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

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






      

       看了那么多理论知识,可能还是一头雾水,是啊,纯理论分析本来就不好理解。为了更好的理解Linux内核各种内部机制以及其运用,在接下来的学习中将采用理论+实验+源码注释的方式进行。包括算法、原理的实验,内核的局部扩展与修改等。Linux内核编程有很多方法,最方便的方式是使用内核提供的模块编程机制,另一种方式是以补丁的方式,这种方式只需要编译一次内核,当然也可以直接修改内核源码,但是每次修改后都需要重新编译、引导、重启,很麻烦,也很费时。首先,我们看看最方便快捷的一种方式——LINUX内核中模块编程机制。

      

      还是从程序员的哪个起步程序hello world开始,但是我们这里比一般的hello world稍微复杂一点,用两个hello world程序。



文件hello.c

[cpp] view plaincopyprint?
  1. #include <linux/init.h>   
  2. #include <linux/module.h>   
  3. #include <linux/kernel.h>   
  4.   
  5. MODULE_LICENSE("GPL");  
  6. extern int hello_data;  
  7.   
  8. static int hello_init(void)  
  9. {  
  10.     printk(KERN_ERR "hello,kernel!,this is hello module\n");  
  11.     printk(KERN_ERR "hello_data:%d\n",++hello_data);  
  12.     return 0;  
  13. }  
  14.   
  15. static void hello_exit(void)  
  16. {  
  17.     printk(KERN_ERR "hello_data:%d\n",--hello_data);  
  18.     printk(KERN_ERR "Leave hello module!\n");  
  19. }  
  20. module_init(hello_init);  
  21. module_exit(hello_exit);  
  22.   
  23. MODULE_AUTHOR("Mike Feng");  
  24. MODULE_DESCRIPTION("This is hello module");  
  25. MODULE_ALIAS("A simple example");  
  26. #include <linux/init.h>
  27. #include <linux/module.h>
  28. #include <linux/kernel.h>

  29. MODULE_LICENSE("GPL");
  30. extern int hello_data;

  31. static int hello_init(void)
  32. {
  33.         printk(KERN_ERR "hello,kernel!,this is hello module\n");
  34.         printk(KERN_ERR "hello_data:%d\n",++hello_data);
  35.         return 0;
  36. }

  37. static void hello_exit(void)
  38. {
  39.         printk(KERN_ERR "hello_data:%d\n",--hello_data);
  40.         printk(KERN_ERR "Leave hello module!\n");
  41. }
  42. module_init(hello_init);
  43. module_exit(hello_exit);

  44. MODULE_AUTHOR("Mike Feng");
  45. MODULE_DESCRIPTION("This is hello module");
  46. MODULE_ALIAS("A simple example");
复制代码
对应的Makefile文件:

[plain] view plaincopyprint?
  1. obj-m +=hello.o  
  2. CURRENT_DIR:=$(shell pwd)  
  3. KERNEL_DIR:=$(shell uname -r)  
  4. KERNEL_PATH:=/usr/src/kernels/$(KERNEL_DIR)  
  5.   
  6. all:  
  7.     make -C $(KERNEL_PATH) M=$(CURRENT_DIR) modules  
  8. clean:  
  9.     make -C $(KERNEL_PATH) M=$(CURRENT_DIR) clean  
  10. obj-m +=hello.o
  11. CURRENT_DIR:=$(shell pwd)
  12. KERNEL_DIR:=$(shell uname -r)
  13. KERNEL_PATH:=/usr/src/kernels/$(KERNEL_DIR)

  14. all:
  15.         make -C $(KERNEL_PATH) M=$(CURRENT_DIR) modules
  16. clean:
  17.         make -C $(KERNEL_PATH) M=$(CURRENT_DIR) clean
复制代码
文件hello_h.c:

[cpp] view plaincopyprint?
  1. #include <linux/init.h>   
  2. #include <linux/module.h>   
  3. #include <linux/kernel.h>   
  4.   
  5. MODULE_LICENSE("GPL");  
  6. static unsigned int hello_data=100;  
  7. EXPORT_SYMBOL(hello_data);  
  8.   
  9. static int hello_h_init(void)  
  10. {  
  11.     hello_data+=5;  
  12.     printk(KERN_ERR "hello_data:%d\nhello kernel,this is hello_h module\n",hello_data);  
  13.   
  14.     return 0;  
  15. }  
  16.   
  17. static void hello_h_exit(void)  
  18. {  
  19.     hello_data-=5;  
  20.     printk(KERN_ERR "hello_data:%d\nleave hello_h module\n",hello_data);  
  21. }  
  22.   
  23. module_init(hello_h_init);  
  24. module_exit(hello_h_exit);  
  25. MODULE_AUTHOR("Mike Feng");  
  26. #include <linux/init.h>
  27. #include <linux/module.h>
  28. #include <linux/kernel.h>

  29. MODULE_LICENSE("GPL");
  30. static unsigned int hello_data=100;
  31. EXPORT_SYMBOL(hello_data);

  32. static int hello_h_init(void)
  33. {
  34.         hello_data+=5;
  35.         printk(KERN_ERR "hello_data:%d\nhello kernel,this is hello_h module\n",hello_data);

  36.         return 0;
  37. }

  38. static void hello_h_exit(void)
  39. {
  40.         hello_data-=5;
  41.         printk(KERN_ERR "hello_data:%d\nleave hello_h module\n",hello_data);
  42. }

  43. module_init(hello_h_init);
  44. module_exit(hello_h_exit);
  45. MODULE_AUTHOR("Mike Feng");
复制代码
对应的Makefile

[plain] view plaincopyprint?
  1. obj-m+=hello_h.o  
  2. CURRENT:=$(shell pwd)  
  3. KERNEL_PATH:=/usr/src/kernels/$(shell uname -r)  
  4.   
  5. all:  
  6.     make -C $(KERNEL_PATH) M=$(CURRENT) modules  
  7. clean:  
  8.     make -C $(KERNEL_PATH) M=$(CURRENT) clean  
  9. obj-m+=hello_h.o
  10. CURRENT:=$(shell pwd)
  11. KERNEL_PATH:=/usr/src/kernels/$(shell uname -r)

  12. all:
  13.         make -C $(KERNEL_PATH) M=$(CURRENT) modules
  14. clean:
  15.         make -C $(KERNEL_PATH) M=$(CURRENT) clean
复制代码
可见,我们在hello_h.c中定义了一个静态变量hello_data,初始值为100,并把他导出了,在hello.c中使用了该变量。这样给出例子,后面我们会看到,是为了说明模块依赖。



模块信息分析初步

       当我们make后,在当前目录下生成文件有:hello.mod.c、hello.o、hello.ko、hello.mod.o、Module.markers、modules.order、Module.symvers。上面的代码以及编译生成的文件后面会详细分析。



hello.ko文件是我们需要的,用file名命令看看。


        file命令的输出表明模块文件是可重定位的,这是用户空间程序设计中一个熟悉的术语。可从定位文件的函数都不会引用绝对地址,而只是指向代码中的相对地址,因此可以在内存的任意偏移地址加载,当然,在映像加载到内存中时,映像个的地址要由动态链接器ld.so进行适当的修改。内核模块同样如此。其中的地址也是相对的,而不是绝对的。当重定位的工作由内核自身执行,而不是动态装载器。



我们再用nm命令查看一下该目标文件的外部函数列表。nm hello.ko:
  1. 00000000 r __mod_alias25
  2. 0000003c r __mod_author23
  3. 00000018 r __mod_description24
  4. 00000050 r __mod_license5
  5. 0000005c r __mod_srcversion23
  6. 0000008c r __mod_vermagic5
  7. 00000080 r __module_depends
  8. 00000000 D __this_module
  9. 00000000 T cleanup_module
  10.          U hello_data
  11. 00000000 t hello_exit
  12. 0000002d t hello_init
  13. 0000002d T init_module
  14.          U mcount
  15.          U printk
复制代码
U代表未解决的引用,可见都为内核代码中的导出函数,D表示符号位于数据段,T表示符号位于代码段。内核提供了一个所有导出函数的列表。该列表给出了所有导出函数的内存地址和对应的函数名,可以通过proc文件系统访问,即文件/proc/kallsyms。



查询模块信息:

        还有一些额外的信息来源,是直接存储在模块二进制文件中,并且指定了模块用途的文本描述。这些可以使用modutils中的modinfo工具查询。他们可以存储电子邮件地址、功能简短描述、配置参数描述、指定支持的设备、模块按何种许可证分发等,我们对上面的hello.ko文件查看一下:



       这些额外的信息如何合并到二进制模块文件中呢?在所有使用ELF格式的二进制文件中,有各种各种单元将二进制数据组织到不同类别中,这些在技术上称之为段。为允许在模块中添加信息,内核引入了一个名为.modinfo的段。

自动加载:

      通常,模块的装载发起于用户空间,由用户或自动化脚本启动。在处理模块时,呜呜i达到更大的灵活性并提高透明度,内核自身也能够请求加载模块。由于在用户空间完成这些比在内核空间容易的多,内核将该工作委托给一个辅助进程kmod。要注意,kmod并不是一个永久性的守护进程,内核会按需启动他。



       当内核请求没有相关数据结构信息时,内核试图使用request_module函数加载对应的模块,该函数使用kmod机制启动modprobe工具,modprobe插入相应的模块。换句话说,内核依赖于用户空间中的一个应用程序使用内核函数来添加模块,如下图:





       内核源代码中,很多不同地方调用了request_module。借助该函数,内核试图通过在没有用户介入的情况下自动加载代码,使得尽可能透明地访问那些委托给模块的功能。



        可能出现这样的情况;无法唯一确定哪个模块能够提供所需的功能。为解决这个问题,附加到每个模块的一个小“数据库”。数据库的内容描述了该模块所支持的设备。数据库信息通过模块别别名提供。这些是模块的通用标识符,其中编码了所描述的信息。宏MODULE_ALIAS用于产生模块别名。MODULE_ALIAS这一类的宏都由MODULE_INFO定义,我们还是从源码中寻找出处:

[cpp] view plaincopyprint?
  1. /* Generic info of form tag = "info" */  
  2. #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)   
  3.   
  4. /* For userspace: you can also call me... */  
  5. #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)   
  6.   
  7.   
  8. #define __MODULE_INFO(tag, name, info)                    \   
  9. static const char __module_cat(name,__LINE__)[]               \  
  10.   __used                                  \  
  11.   __attribute__((section(".modinfo"),unused)) = __stringify(tag)  
  12. /* Generic info of form tag = "info" */
  13. #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)

  14. /* For userspace: you can also call me... */
  15. #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)


  16. #define __MODULE_INFO(tag, name, info)                                          \
  17. static const char __module_cat(name,__LINE__)[]                                  \
  18.   __used                                                                  \
  19.   __attribute__((section(".modinfo"),unused)) = __stringify(tag)
复制代码
可见,MODULE_INFO内容保存在模块二进制文件的.modinfo段中。



模块行为

      用户空间工具和内核的模块实现之间的结构,包括两个系统调用。

init_module:将一个新模块插入到内核中。用户空间工具只需提供二进制数据。所有其他工作(特别是重定位和解决引用)由内核自身完成。



delete_module:从内核溢出一个模块。当然,前提是该模块的代码不再使用,并且其他模块也不再使用该模块导出的函数。



还有一个request_module函数(不是系统调用),用于从内核端加载模块。他不经用于加载模块。还用于实现热插拔功能。



模块在内核中用下面数据结构表示:

[cpp] view plaincopyprint?
  1. struct module  
  2. {  
  3.     enum module_state state;  
  4.   
  5.     /* Member of list of modules */  
  6.     /*链表的表头为一个module类型的全局变量
  7.     modules*/  
  8.     struct list_head list;  
  9.   
  10.     /* Unique handle for this module */  
  11.     char name[MODULE_NAME_LEN];  
  12.   
  13.     /* Sysfs stuff. */  
  14.     struct module_kobject mkobj;  
  15.     struct module_attribute *modinfo_attrs;  
  16.     const char *version;  
  17.     const char *srcversion;  
  18.     struct kobject *holders_dir;  
  19.   
  20.     /* Exported symbols */  
  21.     /*syms为一个数组,共有num_syms项,
  22.     类型kernel_symbol负责将标识符(name字段)
  23.     分配到内存地址(value字段)*/  
  24.     const struct kernel_symbol *syms;  
  25.     /*也是num_syms个项的数组,存放了到处富豪的校验和
  26.     用于实现版本控制*/  
  27.     const unsigned long *crcs;  
  28.     unsigned int num_syms;  
  29.   
  30.     /* Kernel parameters. */  
  31.     struct kernel_param *kp;  
  32.     unsigned int num_kp;  
  33.   
  34.     /* GPL-only exported symbols. */  
  35.     unsigned int num_gpl_syms;  
  36.     const struct kernel_symbol *gpl_syms;  
  37.     const unsigned long *gpl_crcs;  
  38.   
  39. #ifdef CONFIG_UNUSED_SYMBOLS   
  40.     /* unused exported symbols. */  
  41.     const struct kernel_symbol *unused_syms;  
  42.     const unsigned long *unused_crcs;  
  43.     unsigned int num_unused_syms;  
  44.   
  45.     /* GPL-only, unused exported symbols. */  
  46.     unsigned int num_unused_gpl_syms;  
  47.     const struct kernel_symbol *unused_gpl_syms;  
  48.     const unsigned long *unused_gpl_crcs;  
  49. #endif   
  50.   
  51.     /* symbols that will be GPL-only in the near future. */  
  52.     const struct kernel_symbol *gpl_future_syms;  
  53.     const unsigned long *gpl_future_crcs;  
  54.     unsigned int num_gpl_future_syms;  
  55.   
  56.     /* Exception table */  
  57.     unsigned int num_exentries;  
  58.     struct exception_table_entry *extable;  
  59.   
  60.     /* Startup function. */  
  61.     int (*init)(void);  
  62.   
  63.     /* If this is non-NULL, vfree after init() returns */  
  64.     /*模块二进制数据分为两个部分:初始化部分和核心部分
  65.     前者包含的东西在装载结束后都可以丢弃
  66.     后者包含了正常运行期间需要的所有数据
  67.     初始化部分的起始地址保存在module_init*/  
  68.     void *module_init;  
  69.   
  70.     /* Here is the actual code + data, vfree'd on unload. */  
  71.     void *module_core;  
  72.   
  73.     /* Here are the sizes of the init and core sections */  
  74.     unsigned int init_size, core_size;  
  75.   
  76.     /* The size of the executable code in each section.  */  
  77.     unsigned int init_text_size, core_text_size;  
  78.   
  79.     /* Arch-specific module values */  
  80.     struct mod_arch_specific arch;  
  81.   
  82.     unsigned int taints;    /* same bits as kernel:tainted */  
  83.   
  84. #ifdef CONFIG_GENERIC_BUG   
  85.     /* Support for BUG */  
  86.     unsigned num_bugs;  
  87.     struct list_head bug_list;  
  88.     struct bug_entry *bug_table;  
  89. #endif   
  90.   
  91. #ifdef CONFIG_KALLSYMS   
  92.     /*
  93.      * We keep the symbol and string tables for kallsyms.
  94.      * The core_* fields below are temporary, loader-only (they
  95.      * could really be discarded after module init).
  96.      */  
  97.     Elf_Sym *symtab, *core_symtab;  
  98.     unsigned int num_symtab, core_num_syms;  
  99.     char *strtab, *core_strtab;  
  100.   
  101.     /* Section attributes */  
  102.     struct module_sect_attrs *sect_attrs;  
  103.   
  104.     /* Notes attributes */  
  105.     struct module_notes_attrs *notes_attrs;  
  106. #endif   
  107.   
  108.     /* Per-cpu data. */  
  109.     void *percpu;  
  110.   
  111.     /* The command line arguments (may be mangled).  People like
  112.        keeping pointers to this stuff */  
  113.     char *args;  
  114. #ifdef CONFIG_TRACEPOINTS   
  115.     struct tracepoint *tracepoints;  
  116.     unsigned int num_tracepoints;  
  117. #endif   
  118.   
  119. #ifdef CONFIG_TRACING   
  120.     const char **trace_bprintk_fmt_start;  
  121.     unsigned int num_trace_bprintk_fmt;  
  122. #endif   
  123. #ifdef CONFIG_EVENT_TRACING   
  124.     struct ftrace_event_call *trace_events;  
  125.     unsigned int num_trace_events;  
  126. #endif   
  127. #ifdef CONFIG_FTRACE_MCOUNT_RECORD   
  128.     unsigned long *ftrace_callsites;  
  129.     unsigned int num_ftrace_callsites;  
  130. #endif   
  131.   
  132. #ifdef CONFIG_MODULE_UNLOAD   
  133.     /* What modules depend on me? */  
  134.     /*将依赖本模块的模块用module_use数据结构链接
  135.     起来*/  
  136.     struct list_head modules_which_use_me;  
  137.   
  138.     /* Who is waiting for us to be unloaded */  
  139.     struct task_struct *waiter;  
  140.   
  141.     /* Destruction function. */  
  142.     void (*exit)(void);  
  143.   
  144. #ifdef CONFIG_SMP   
  145.     char *refptr;  
  146. #else   
  147.     local_t ref;  
  148. #endif   
  149. #endif   
  150.   
  151. #ifdef CONFIG_CONSTRUCTORS   
  152.     /* Constructor functions. */  
  153.     ctor_fn_t *ctors;  
  154.     unsigned int num_ctors;  
  155. #endif   
  156. };  
  157. struct module
  158. {
  159.         enum module_state state;

  160.         /* Member of list of modules */
  161.         /*链表的表头为一个module类型的全局变量
  162.         modules*/
  163.         struct list_head list;

  164.         /* Unique handle for this module */
  165.         char name[MODULE_NAME_LEN];

  166.         /* Sysfs stuff. */
  167.         struct module_kobject mkobj;
  168.         struct module_attribute *modinfo_attrs;
  169.         const char *version;
  170.         const char *srcversion;
  171.         struct kobject *holders_dir;

  172.         /* Exported symbols */
  173.         /*syms为一个数组,共有num_syms项,
  174.         类型kernel_symbol负责将标识符(name字段)
  175.         分配到内存地址(value字段)*/
  176.         const struct kernel_symbol *syms;
  177.         /*也是num_syms个项的数组,存放了到处富豪的校验和
  178.         用于实现版本控制*/
  179.         const unsigned long *crcs;
  180.         unsigned int num_syms;

  181.         /* Kernel parameters. */
  182.         struct kernel_param *kp;
  183.         unsigned int num_kp;

  184.         /* GPL-only exported symbols. */
  185.         unsigned int num_gpl_syms;
  186.         const struct kernel_symbol *gpl_syms;
  187.         const unsigned long *gpl_crcs;

  188. #ifdef CONFIG_UNUSED_SYMBOLS
  189.         /* unused exported symbols. */
  190.         const struct kernel_symbol *unused_syms;
  191.         const unsigned long *unused_crcs;
  192.         unsigned int num_unused_syms;

  193.         /* GPL-only, unused exported symbols. */
  194.         unsigned int num_unused_gpl_syms;
  195.         const struct kernel_symbol *unused_gpl_syms;
  196.         const unsigned long *unused_gpl_crcs;
  197. #endif

  198.         /* symbols that will be GPL-only in the near future. */
  199.         const struct kernel_symbol *gpl_future_syms;
  200.         const unsigned long *gpl_future_crcs;
  201.         unsigned int num_gpl_future_syms;

  202.         /* Exception table */
  203.         unsigned int num_exentries;
  204.         struct exception_table_entry *extable;

  205.         /* Startup function. */
  206.         int (*init)(void);

  207.         /* If this is non-NULL, vfree after init() returns */
  208.         /*模块二进制数据分为两个部分:初始化部分和核心部分
  209.         前者包含的东西在装载结束后都可以丢弃
  210.         后者包含了正常运行期间需要的所有数据
  211.         初始化部分的起始地址保存在module_init*/
  212.         void *module_init;

  213.         /* Here is the actual code + data, vfree'd on unload. */
  214.         void *module_core;

  215.         /* Here are the sizes of the init and core sections */
  216.         unsigned int init_size, core_size;

  217.         /* The size of the executable code in each section.  */
  218.         unsigned int init_text_size, core_text_size;

  219.         /* Arch-specific module values */
  220.         struct mod_arch_specific arch;

  221.         unsigned int taints;        /* same bits as kernel:tainted */

  222. #ifdef CONFIG_GENERIC_BUG
  223.         /* Support for BUG */
  224.         unsigned num_bugs;
  225.         struct list_head bug_list;
  226.         struct bug_entry *bug_table;
  227. #endif

  228. #ifdef CONFIG_KALLSYMS
  229.         /*
  230.          * We keep the symbol and string tables for kallsyms.
  231.          * The core_* fields below are temporary, loader-only (they
  232.          * could really be discarded after module init).
  233.          */
  234.         Elf_Sym *symtab, *core_symtab;
  235.         unsigned int num_symtab, core_num_syms;
  236.         char *strtab, *core_strtab;

  237.         /* Section attributes */
  238.         struct module_sect_attrs *sect_attrs;

  239.         /* Notes attributes */
  240.         struct module_notes_attrs *notes_attrs;
  241. #endif

  242.         /* Per-cpu data. */
  243.         void *percpu;

  244.         /* The command line arguments (may be mangled).  People like
  245.            keeping pointers to this stuff */
  246.         char *args;
  247. #ifdef CONFIG_TRACEPOINTS
  248.         struct tracepoint *tracepoints;
  249.         unsigned int num_tracepoints;
  250. #endif

  251. #ifdef CONFIG_TRACING
  252.         const char **trace_bprintk_fmt_start;
  253.         unsigned int num_trace_bprintk_fmt;
  254. #endif
  255. #ifdef CONFIG_EVENT_TRACING
  256.         struct ftrace_event_call *trace_events;
  257.         unsigned int num_trace_events;
  258. #endif
  259. #ifdef CONFIG_FTRACE_MCOUNT_RECORD
  260.         unsigned long *ftrace_callsites;
  261.         unsigned int num_ftrace_callsites;
  262. #endif

  263. #ifdef CONFIG_MODULE_UNLOAD
  264.         /* What modules depend on me? */
  265.         /*将依赖本模块的模块用module_use数据结构链接
  266.         起来*/
  267.         struct list_head modules_which_use_me;

  268.         /* Who is waiting for us to be unloaded */
  269.         struct task_struct *waiter;

  270.         /* Destruction function. */
  271.         void (*exit)(void);

  272. #ifdef CONFIG_SMP
  273.         char *refptr;
  274. #else
  275.         local_t ref;
  276. #endif
  277. #endif

  278. #ifdef CONFIG_CONSTRUCTORS
  279.         /* Constructor functions. */
  280.         ctor_fn_t *ctors;
  281.         unsigned int num_ctors;
  282. #endif
  283. };
复制代码
module_state状态:

[cpp] view plaincopyprint?
  1. enum module_state  
  2. {  
  3.     /*正常运行*/  
  4.     MODULE_STATE_LIVE,  
  5.     /*装载期间*/  
  6.     MODULE_STATE_COMING,  
  7.     /*正在移除*/  
  8.     MODULE_STATE_GOING,  
  9. };  
  10. enum module_state
  11. {
  12.         /*正常运行*/
  13.         MODULE_STATE_LIVE,
  14.         /*装载期间*/
  15.         MODULE_STATE_COMING,
  16.         /*正在移除*/
  17.         MODULE_STATE_GOING,
  18. };[cpp] view plaincopyprint?
  19. struct kernel_symbol  
  20. {  
  21.     unsigned long value;  
  22.     const char *name;  
  23. };  
  24. struct kernel_symbol
  25. {
  26.         unsigned long value;
  27.         const char *name;
  28. };
复制代码
依赖关系和引用:

如果模块B使用了模块A提供的函数,那么模块A和模块B之间就存在关系。为正确管理这些依赖关系,内核需要引入另一个数据结构:

[cpp] view plaincopyprint?
  1. /* modules using other modules */  
  2. struct module_use  
  3. {  
  4.     struct list_head list;  
  5.     struct module *module_which_uses;  
  6. };  
  7. /* modules using other modules */
  8. struct module_use
  9. {
  10.         struct list_head list;
  11.         struct module *module_which_uses;
  12. };
复制代码
依赖关系的网络通过module_use和module数据结构的modules_which_use_me成员共同建立起来。对每个使用了模块A中函数的模块B,都会创建一个module_use的新实例。该实例将添加到模块A的modules_which_use_me链表中。Module_which_uses指向模块B的module实例。根据这些信息,内核很容易计算出使用特定模块的其他内核模块。我们回到前面的两个hello kernel代码,hello.c中用了一个外部变量hello_data,这个变量来自hello_h.c中,为hello_h.c的全局静态导出变量。所以hello模块依赖hello_h模块。我们正常操作:先插入模块hello_h然后插入hello模块,先移除hello模块,在移除hello_h:



很容易想到上面的操作顺序是不能改变的。



上面的依赖关系可以画出如下图:





       当然,有数据结构必然有操作这些数据结构的函数,数据结构放这里了,对于他的操作就不看了。无非是从hello找到hello_h。



模块的二进制结构:

我们使用readelf –S hello.ko > readelf.txt命令来看看hello.ko模块文件的二进制结构,输出如下:

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP