Modultils工具源码分析之insmod篇 (1)

来源:互联网 发布:全球反倾销数据库 编辑:程序博客网 时间:2024/05/15 02:25

这系列是几年前发的。现在回过头看,还是蛮有意思的。把它们一起放上来。

 

Modultils工具源码分析之insmod

 

作者:吴晖

20051229

前言

Linux的前身UNIX是一个巨内核操作系统,这样的系统运行效率高,但是内核占据的资源比较多,而且更要命的是系统在启动时必须把所有的设备驱动都加载,不管有没有用。另外,每添加或修改驱动都要重新编译内核。在各种设备层出不穷,日新月异的今天,这有点不合时宜了。

作为另一种解决方案,卡奈基·梅隆大学开发了UNIX的微内核变种mach。这个操作系统表现出了许多先进的特性,拥有传统UNIX所不具备的性能。但是微内核把许多传统上属于内核的功能,象文件系统丢到了用户空间,使其只能通过IPC与内核交互,一定程度上影响了效率。

“不站左、不站右、站中间”,Linux暗合中国的中庸文化,整出了可加载模块这一方案。在这方案里原来属于内核的东西还是归内核,但是象文件系统、设备驱动,这样的东西都可以做成可动态添加、卸载。需要的时候添加,不需要的时候卸载,随时保持内核最小。

粗粗一看,这有点像我们做的动态库,但是又不一样。动态库可以导出一系列变量、函数供外部使用,但它自己不能引用库以外的变量、函数。显然,文件系统、设备驱动不可能不使用内核中的函数。内核倒更像动态库,它不会使用模块导出的变量、函数(因为无法预测),相反它会导出一堆变量、函数给模块用。可关键是,内核必须是可执行程序,像动态库这样等着别人来调用,万万不行!

伤脑筋呵?

其实还好,既然内核有动态库这样的特性就可以了,那么事情就不是那么复杂了。而模块呢,一方面它会导出变量和函数给别的後加载的模块使用,另一方面,它要使用内核和已加载模块导出的变量和函数。毫无疑问,模块使用的文件必须是可重定位的。因此,模块使用的是elf文件格式。Elf文件的全称是Executable and Linkable Format

Elf文件格式的可能布局如下图。


在上图中,程序头(program Header)对于.o目标文件是没有意义的(模块文件正是这样的文件),而在运行执行文件和库文件时,系统一般只理会程序头,因为程序头已经给出了足够的信息,这里的程序头就是我们平常看到的segment(进程就是以segment组织起来的,可以参考linuxbinfmt_elf.c文件里elf文件加载的代码)。另外,值得注意的是,segment的内容可以与段的内容重叠(一般也会重叠),segment和段只不过是描述程序数据的不同方式。

对于.o目标文件来说,程序头一般是不存在的(因为还没完成外部符号解析及与其他目标文件的链接,无法确定进程的内存布局)。因此对于.o目标文件来说,信息都保存在段(section)中。

段根据其保存内容的不同,分为字符段、符号段、数据段、代码段、静态初始化数据段(.bss)、重定位段、注释段、Global offset table(我不知道怎么翻译贴切)段、等等。

这些段中最重要的段是符号段和重定位段。

2个段的关系,见下图。


符号段保存了模块所有的符号,包括模块定义的,以及模块引用外部的。符号段保存的是一个个固定大小的单元。每个单元,保存着关于这个符号的信息。这些信息里面最重要的就是符号的值,这个值对于引用外部变量,是边界对齐要求(因为对于引用外部变量,变量的地址只能在链接时确定,编译时无法知道哪怕一丁点的信息),对于其他文件内定义的变量,这个值保存的是从保存它的段(注意不是保存符号信息的段)起始到符号位置的偏移,基本上就是变量的相对地址。

重定位段则保存相应符号的重定位信息、离所在段起始的偏移,重定位段中的每一单元都是对应一个符号。从重定位段出发就可以找到所有需要重定位的符号所在的段,进而找到符号的信息。然后根据重定位段给出的重定位操作信息,就可以计算、设置符号的绝对地址。

而内核为了导出符号给模块,将要导出的符号存放在__kallsyms这样一个段(模块也一样),并专门提供了个sys_query_module这样的系统调用(v2.1.x以后的版本),模块通过这个调用可以查询内核和其他已加载模块导出的符号。

不过即便已经有了这些便利,加载模块还是一个不轻松的工作(它的工作内容和链接多个.o文件相仿)。为此,出现了专门的工具,这就是modutils系列。Modutils包含好几个工具:insmodrmmoddepmodmodprobelsmodkerneldksymskallsyms。其中的insmod就是用来加载模块的,而rmmod则是卸载模块。

这里由于时间和篇幅,我们暂时只讨论insmod。其他,以后有时间,会尽量补上。选择insmod的原因,是因为它的工作和GNUld类似,读懂了它就能大致明白ld的原理,还有就是能了解elf文件格式。

虽然insmod的代码相当长,但是它的逻辑并不复杂。基本流程如下图。


 

 

原创粉丝点击