您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > Linux操作系统分析与实践
Linux操作系统分析与实践实验二:内存管理《Linux操作系统分析与实践》课程建设小组北京大学二零零八年春季*致谢:感谢Intel对本课程项目的资助实验目的•1.理解Linux虚拟内存管理的机制。•2.学习模块编程的基本技能。实验内容1.模块编写一个内核模块,分别实现如下几个函数:staticvoidmtest_dump_vma_list(void):依次列出当前进程各段的读、写或执行权限。staticvoidmtest_find_vma(unsignedlongaddr):找到虚地址addr所在的vma,通过printk打印该段的起始地址、终止地址、段标志等信息。staticvoidmtest_find_page(unsignedlongaddr):找到虚拟地址addr,显示出其对应的物理地址。为了测试和使用以上函数,在内核模块的初始化函数中创建一个名为mtest的/proc文件。mtest文件绑定的写函数mtest_write允许用户程序写入一串字符串,指定要使用以上的那个内核函数及其参数。mtest_write函数的定义为:staticssize_tmtest_write(structfile*file,constchar__user*buffer,size_tcount,loff_t*data)2.测试程序为了测试以上模块的正确性,要求编写一个称为test的应用程序,它通过打开/proc文件mtest,调用模块内的相关函数并给出相应的测试信息。Linux内核模块•Linux操作系统的内核是单一体系结构(monolithickernel)•有了模块机制后,提高Linux操作系统的可扩充性,内核编程不再是一个恶梦•什么是模块呢?•模块的全称是“动态可加载内核模块”(LoadableKernelModule,LKM)•模块在内核空间运行•模块实际上是一种目标对象文件•没有链接,不能独立运行,但是其代码可以在运行时链接到系统中作为内核的一部分运行或从内核中取下,从而可以动态扩充内核的功能•这种目标代码通常由一组函数和数据结构组成①Linux内核模块的优点与缺点•优点–使得内核更加紧凑和灵活–修改内核时,不必全部重新编译整个内核。系统如果需要使用新模块,只要编译相应的模块,然后使用insmod将模块装载即可–模块的目标代码一旦被链接到内核,它的作用域和静态链接的内核目标代码完全等价•缺点–由于内核所占用的内存是不会被换出的,所以链接进内核的模块会给整个系统带来一定的性能和内存利用方面的损失;–装入内核的模块就成为内核的一部分,可以修改内核中的其他部分,因此,模块的使用不当会导致系统崩溃;–为了让内核模块能访问所有内核资源,内核必须维护符号表,并在装入和卸载模块时修改符号表;–模块会要求利用其它模块的功能,所以,内核要维护模块之间的依赖性.②Linux内核模块与应用程序的区别C语言程序Linux内核模块运行用户空间内核空间入口main()module_init()指定;出口无module_exit()指定;编译gcc–cMakefile连接ldinsmod运行直接运行insmod调试gdbkdbug,kdb,kgdb等③模块相关命令•insmodmodule.ko[moduleparameters]–Loadthemodule–注意,只有超级用户才能使用这个命令•Rmmod–Unloadthemodule•lsmod–Listallmodulesloadedintothekernel–这个命令和cat/proc/modules等价•modprobe[-r]modulename––Loadthemodulespecifiedandmodulesitdepends④模块依赖•一个模块A引用另一个模块B所导出的符号,我们就说模块B被模块A引用。•如果要装载模块A,必须先要装载模块B。否则,模块B所导出的那些符号的引用就不可能被链接到模块A中。这种模块间的相互关系就叫做模块依赖。⑤最简单的内核模块例子#includelinux/kernel.h#includelinux/module.h#includelinux/init.hstaticint__inithello_init(void){printk(KERN_INFOHelloworld\n);return0;}staticvoid__exithello_exit(void){printk(KERN_INFOGoodbyeworld\n);}module_init(hello_init);module_exit(hello_exit);•staticint__inithello_init(void)•staticvoid__exithello_exit(void)–Static声明,因为这种函数在特定文件之外没有其它意义–__init标记,该函数只在初始化期间使用。模块装载后,将该函数占用的内存空间释放–__exit标记该代码仅用于模块卸载。•Init/exit–宏:module_init/module_exit–声明模块初始化及清除函数所在的位置–装载和卸载模块时,内核可以自动找到相应的函数module_init(hello_init);module_exit(hello_exit);⑥编译内核模块•Makefile文件obj-m:=hello.oall:make-C/lib/modules/$(shelluname-r)/buildM=$(shellpwd)modulesclean:make-C/lib/modules/$(shelluname-r)/buildM=$(shellpwd)clean•Moduleincludesmorefilesobj-m:=hello.ohello-objs:=a.ob.o⑦装载和卸载模块•相关命令–lsmod–insmodhello.ko–rmmodhello.ko⑧模块参数传递•有些模块需要传递一些参数•参数在模块加载时传递#insmodhello.kotest=2•参数需要使用module_param宏来声明module_param的参数:变量名称,类型以及访问许可掩码•支持的参数类型Byte,short,ushort,int,uint,long,ulong,bool,charpArray(module_param_array(name,type,nump,perm))#includelinux/kernel.h#includelinux/module.h#includelinux/init.h#includelinux/moduleparam.hstaticinttest;module_param(test,int,0644);staticint__inithello_init(void){printk(KERN_INFO“Helloworldtest=%d\n”,test);return0;}staticvoid__exithello_exit(void){printk(KERN_INFOGoodbyeworld\n);}MODULE_LICENSE(GPL);MODULE_DESCRIPTION(Test);MODULE_AUTHOR(xxx);module_init(hello_init);module_exit(hello_exit);运行结果导出符号表•如果一个模块需要向其他模块导出符号(方法或全局变量),需要使用:EXPORT_SYMBOL(name);EXPORT_SYMBOL_GPL(name);*注意:符号必须在模块文件的全局部分导出,不能在函数部分导出。更多信息可参考linux/module.h文件•Modules仅可以使用由Kernel或者其他Modules导出的符号不能使用Libc•/proc/kallsyms可以显示所有导出的符号⑨内核模块操作/proc文件•/proc文件系统,这是内核模块和系统交互的两种主要方式之一。•/proc文件系统也是Linux操作系统的特色之一。•/proc文件系统不是普通意义上的文件系统,它是一个伪文件系统。•通过/proc,可以用标准Unix系统调用(比如open()、read()、write()、ioctl()等等)访问进程地址空间•可以用cat、more等命令查看/proc文件中的信息。•用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。•当调试程序或者试图获取指定进程状态的时候,/proc文件系统将是你强有力的支持者。通过它可以创建更强大的工具,获取更多信息。Q&A开始实验!参考实验指导书完成本次实验
本文标题:Linux操作系统分析与实践
链接地址:https://www.777doc.com/doc-3871338 .html