这篇文章主机频道详细介绍了“linux引入模块机制有什么好处”。内容详细,步骤清晰,细节处理得当。希望这篇文章《linux引入模块机制有什么好处》能帮你解决疑惑。让我们按照主机频道的思路,一起学习新知识。
在linux中引入模块机制的优点如下:1 .当应用程序退出时,它可以忽略资源的释放或其他清理工作,但模块的退出函数必须仔细撤销初始化函数所做的一切;2.这种机制有助于缩短模块的开发周期,即注册和卸载灵活方便。
Linux引入模块机制有什么好处?首先,模块预先注册自己以服务未来的请求,然后它的初始化功能立即结束。换句话说,模块初始化函数的任务就是为后面调用函数做准备。
好处:
1)当应用程序退出时,可以忽略资源的释放或其他清理工作,但模块的退出函数必须仔细撤销初始化函数所做的一切。
2)这种机制有助于缩短模块的开发周期。也就是注册和卸载都非常灵活方便。
Linux模块机制分析Linux允许用户通过插入模块来干预内核。长期以来,linux的模块机制不够清晰,本文简单分析内核模块的加载机制。
你好模块世界!
我们通过创建一个简单的模块进行测试。第一个是源文件main.c和Makefile。
Florian @ Florian-PC:~/module $ cat main . c
# include & ltLinux/module . h & gt;# include & ltLinux/init . h & gt;static int _ _ init init(void){ printk(& quot;嗨模块!\ n & quot);返回0;}静态void _ _ exit exit(void){ printk(& quot;再见模块!\ n & quot);} module_init(初始化);module_exit(退出);Init是模块入口函数,在模块加载时调用并执行,exit是模块出口函数,在模块卸载时调用并执行。
Florian @ Florian-PC:~/module $ cat Makefile
obj-M+= main . o #生成PATH CURRENT _ PATH:= $(shell pwd)#当前内核版本号LINUX_KERNEL:=$(shell uname -r)#绝对路径LINUX _ KERNEL _ PATH:=/usr/src/LINUX-headers-$(LINUX _ KERNEL)# compile object all:make-C $(LINUX _ KERNEL _ PATH)M = $(CURRENT _ PATH)Modules # clean clean:make-C $(LINUX _ KERNEL _ PATH)M = $(CURRENT _ PATH)clean
然后用make命令编译该模块,以获得模块文件main.ko
Florian @ Florian-PC:~/module $ make
make-c/usr/src/Linux-headers-2 . 6 . 35-22-generic m =/home/Florian/module modules make[1]:进入目录`/usr/src/Linux-headers-2 . 6 . 35-22-generic & # 39;构建模块,stage2.modpost1modules make [1]:离开目录`/usr/src/Linux-headers-2 . 6 . 35-22-generic & # 39;使用insmod和rmmod命令加载和卸载模块,使用dmesg打印内核日志。
Florian @ Florian-PC:~/module $ sudo insmod main . ko;dmesg | tail -1[31077.810049] Hi模块!Florian @ Florian-PC:~/module $ sudo rmmod main . ko;dmesg | tail -1[31078.960442] Bye模块!通过内核日志信息,我们可以看到模块的入口函数和出口函数被正确调用和执行。
模块文件
使用readelf命令检查模块文件main.ko的信息
Florian @ Florian-PC:~/module $ readelf-h main . ko
精灵头:魔法:7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00类:ELF32数据:2 & # 39;s补码, 小端版本:1(当前)OS/ ABI: UNIX - System V ABI版本:0类型:REL(可重定位文件)机器:Intel 80386版本:0x1入口点地址:0x0程序头开始ers: 0(进入文件的字节数)段头开始:1120(进入文件的字节数)标志:0x0此头的大小:52(字节)程序头的大小:0(字节)程序头的数量:0段头的大小:40(字节) 节头个数:19节头字符串表索引:16我们发现main.ko的文件类型是一个可重定位的目标文件,和一般的目标文件格式没有区别。 我们知道,目标文件是不能直接执行的,需要经过地址空间分配、符号解析、链接器重定位后,才能转换成可执行文件。
那么内核加载main.ko后,是否链接?
模块数据结构
首先,我们来看看模块的内核数据结构。
Linux 3 . 5 . 2/内核/模块. h:220
结构模块{ …… /*启动函数。*/int(* init)(void);…… /*销毁功能。*/void(*退出)(void);……};模块数据结构的init和exit函数指针记录了我们定义的模块入口函数和出口函数。
模块加载
模块加载由内核系统调用init_module完成。
Linux 3 . 5 . 2/内核/模块. c:3009
/*这是真正工作发生的地方*/SYSCALL_DEFINE3(init_module,void __user *,umod,unsigned long,len,const char __user *,uargs){ struct module * mod;int ret = 0;…… /*做所有的苦工*/ mod = load_module(umod,len,uargs);//模块加载.../*启动模块*/if (mod-> init!= NULL)ret = do _ one _ init call(mod-& gt;init);//模块初始化函数调用...返回0;}系统调用init_module由SYSCALL_DEFINE3(init_module)实现...),还有两个关键的函数调用。Load_module用于模块加载,do_one_initcall用于回调模块的init函数。
函数load_module实现为。
Linux 3 . 5 . 2/内核/模块. c:2864
/*分配和加载模块:注意,第0节的大小始终为零,我们依赖于此作为可选节。*/static struct module * load _ module(void _ _ user * umod,unsigned long len,const char _ _ user * uargs){ struct load _ info info = { NULL,};结构模块* mod长错误;…… /*从用户空间复制blobs,检查它们是否正常。*/ err =复制并检查(& ampinfo,umod,len,uargs);//复制到内核if (err)返回ERR _ PTR(ERR);/*找出模块布局,并分配所有内存。*/mod = layout _ and _ allocate(& amp;info);//地址空间分配if(is _ err(mod)){ err = ptr _ err(mod);goto free _ copy} …… /*修复syms,使st_value成为指向位置的指针。*/err = simplify _ symbols(mod & amp;info);//符号解析if (err
因此,当模块被加载时,内核链接模块文件main.ko!
至于函数do_one_initcall的实现,比较简单。
linux3.5.2/kernel/init.c:673
int _ _ init _ or _ module do _ one _ init call(init call _ t fn){ int count = preempt _ count();int retif(init call _ debug)ret = do _ one _ init call _ debug(fn);else ret = fn();//调用initmodule...返回ret}即调用模块的入口函数init。
模块卸载
模块卸载由内核系统调用delete_module完成。
Linux 3 . 5 . 2/内核/模块. c:768
SYSCALL_DEFINE2(delete_module,const char __user *,name_user,unsigned int,flags){ struct module * mod;char NAME[模块名称长度];int ret,forced = 0;…… /*最终毁灭现在没人用了。*/if(mod->;退出!= NULL)mod-& gt;exit();//调用退出模块...free _ mod(mod);//卸载模块...}通过回调exit完成模块的导出功能,最后调用free_module卸载模块。
评论前必须登录!
注册