7.1-7.2:
1. 可以用nm命令列出模块内使用的函数和全局变量。如:
> nm test.ko
0000003c r __mod_author109
0000000c r __mod_description110
00000000 r __mod_license111
00000074 r __mod_vermagic5
00000068 r __module_depends
00000000 D __this_module
00000000 S bb
00000000 T cleanup_module
00000000 T init_module
U printk
00000000 t test_exit
00000000 t test_init
00000000 B timer
r:表示符号在“只读”数据区,
D:表示符号在“初始化了的”数据区
S:表示符号在“未初始化”数据区
T:在文本区
U:符号未定义,此符号必须已经编译进内核,否则模块加载或运行不成功
B:在未初始化的数据区,即BSS
Note: 更多定义见:man nm
如果KALLSYMS_ALL开始了,则可以用以下命令显示内核已经存在的符号定义:
> cat /proc/kallsyms |grep "xxx"
2. 模块间可能有依赖关系,其依赖关系存放在下面文件:
> cat /lib/modules/kernel version/modules.dep
/lib/modules/2.6.32/kernel/drivers/video/backlight/backlight.ko:
/lib/modules/2.6.32/kernel/drivers/video/backlight/lcd.ko:
/lib/modules/2.6.32/kernel/drivers/video/backlight/generic_bl.ko: /lib/modules/2.6.32/kernel/drivers/video/backlight/backlight.ko
/lib/modules/2.6.32/kernel/drivers/scsi/scsi_wait_scan.ko:
前面的模块依赖于后面的模块。
模块依赖文件的产生是用depmod命令产生,它产生所有模块以及内核的符号列表,然后分析出依赖关系。
3. modinfo xxx.ko 可以列出模块的一些有用信息
4. 有些模块需要提供更多的信息给内核,如PCI,USB等,这些信息通常用MODULE_ALIAS来提供,这些信息是通过 scripts/mod/file2alias.c脚本来分析产生 .mod.c文件给内核提供信息。
7.3 section
1. 模块的三种状态:
enum module_state
{
MODULE_STATE_LIVE,
MODULE_STATE_COMING,
MODULE_STATE_GOING,
};
LIVE:表示完成了初始化,正常工作状态
COMING:装载期间
GOING:卸载状态
2. 模块的两种依赖关系:
A依赖于B或B引用A。
3.模块的参数:struct list modules_which_use_me, 表示所有引用该模块的模块
4. struct module_use
{
struct list_head list;
struct module *module_which_uses;
}; 表示模块所使用的其它模块。
5. 模块产生的步骤:
A:先把.C文件编译为.o文件
B:编译所有其它的模块文件,并分析其依赖关系,生成.mod.c文件
C:链接生成最终文件(有可能插入了其它模块的信息,因为有依赖关系).
6. module_init为模块的初始化文件
module_exit为模块的退出文件。
如果该模块没有被定义为模块类型,则module_init被放到内核的指定段中,一般为.init.section. 否则module_init为普通文件,否则会被定义为普通文件。init文件会在初始化完成后释放。
7. 模块被加载时必须和内核保持版本的一致,匹配的信息包括:
A:SMP开启与否
B:抢占是否被配置
C:编译器的版本
D:架构特定的要求
8. 插入模块的执行流程:
kernel/module.c
init_module
|-->load_module
|-->insert module into kernel list
|-->mod->init
|-->free init area
9. 删除模块的流程:
kernel/module.c
delete_module
|-->find module
|-->ensure module is not used
|-->mod->exit
|-->free_module
7.4
1. 模块有可能在下面两种情况下被自动加载:
A:内核发现需要的函数不可用,会试图加载相应的模块来实现需要的函数
B:新设备加到了支持热插拔的总线,如USB,PCI等
2. 自动加载由request_module函数实现,定义在kernel/kmod.c中,如果内核不支持模块,则该函数定义为空。内核必须在需要加载模块的地方显示调用该函数。
3. request_module实现过程:
kernel/kmod.c
request_module
|-->Prepare environment for modprobe
|-->Too many simultaneous calls of request_module? return
|-->call_usermodehelper
默认会调用/sbin/modprobe用户层程序去加载模块
4. 热拔插会调用/sbin/udevd用户层程序
7.5
1. 为了应对内核版本变化,模块无法加载的问题,模块使用了CRC的机制。即:把模块导出的函数的参数由函数(位于scripts/genksyms/genksym)生成CRC码,并保存在模块文件最后生成的二进制代码段中,加载时内核比较这个CRC,如果不同,说明接口发生了变量,不能加载成功。
阅读(1274) | 评论(0) | 转发(0) |