1、精简内核
与传统嵌入式操作系统的微内核(Micro-kerne1)体系结构不同,Linux内核采用的是整体式结构(Monolithic),整个内核是一个单独的、非常大的程序。其优点是能够使系统的各个部分直接沟通,有效地缩短任务之间的切换时间,提高系统响应速度。缺点也是明显的,即内核尺寸比较大,因为Linux内核不仅包括如任务调度、内存管理、中断处理等基本的操作系统功能,同时还包括文件系统、网络协议、没备驱动程序等功能。
Linux内核是高度模块化、可配置的,通过配置使内核具有不同的功能,从而减小内核的大小。例如,Linux支持的文件系统种类很多,包括ext2、ext3、FAT、Reiserfs、JFS等。可以根据实际情况选择所需的文件系统,比如仅仅把ext2文件系统编译进内核。编译内核的主要步骤如下(“#”代表命令提示符):
# cd/usr/SRC/1inux-2.4
# make menuconfig
# make dep;make clean;make bzlmage
编译成功的内核文件为arch/i386/boot/bzlmage。具体方法参考内核源代码包中的README文件。为了进一步增加灵活性、减小内核尺寸,Linux还提供了可加载内核模块机制,内核中的很多功能可以编译为模块,在内核运行时动态加载,而不是直接编译进内核。然而在嵌入式Linux系统中更倾向于根据需要编译一个独立的内核,较少使用模块机制。这样得到的内核通常在几百kB甚至1MB左右,相对传统的嵌入式操作系统内核来说是比较大的(比如包含文件系统和网络支持的VxWorks内核大约250kB)。在进行内核配置时,开发者要比较了解各功能模块之间的依赖关系,否则有可能造成编译失败。而在VxWorks内核的配置过程中,如果破坏了依赖关系,有比较明确的指示,从而避免这种错误。
2、共享库裁剪
在小型化技术中,共享库裁剪容易用软件实现,做成自动裁剪工具,效果最明显。下面重点介绍共享库小型化技术,共享库小型化的基本思想是通过提取和解析系统库内目标文件、符号的依赖关系,通过对这些依赖构造关系模型进行关系演算,根据应用程序中的符号信息,在库目标文件一级实现系统库的小型化.实现上分为四步:a、确定待调函数集。在ELF文件内部,存在一个Elf32-Sym 数组结构的符号表,用于内部符号定义和外部符号引用,通过对这个符号表的分析可以将ELF应用程序中待调符号(系统函数)抽取出来,从而建立一个应用程序-待调函数符号的多对多关系。b、确定系统库函数与目标文件的对应关系。系统库逻辑上分成:库、目标文件、符号三个层次,库和目标文件都是ELF格式,通过对库的映像文件*_pic.a和每个目标文件中的符号表分析得到库。目标文件的定义关系、目标文件-符号定义关系和目标文件-符号调用关系。c、确定系统库目标文件之间的相互依赖关系。通过对步骤b中相关关系的关系演算得到目标文件-目标文件的完全依赖关系。d、生成小型化系统库。通过对应用程序-待调符号表和目标文件-目标文件依赖表的关系演算得到待调函数所依赖的目标文件集合,将它们进行重新链接即可得到最小化的库文件。
2.1、共享库裁剪技术的原理
共享库中保存着预先编译好的目标代码,一般是被应用程序反复使用的公用代码。在Linux系统中,应用程序与库之间可以静态链接或动态链接。静态链接时,链接器从库中选取应用程序需要的代码,然后复制到生成的可执行文件中。显然,当静态库被多个程序使用时,磁盘上、内存中都是多份冗余拷贝。动态链接时,链接器并不真的把库代码复制到可执行文件中;仅当可执行文件运行时,加载器才检查该库是否已经被其它可执行文件加载进内存,如果内存中不存在才从磁盘上加载该库。这样多个应用程序就可以共享库中的代码的同一份拷贝,节约了存储空间。这也是嵌入式Linux系统使用共享库的主要原因。
当使用静态链接库时,链接器会自动地只把库中被使用的模块链接到可执行文件中。但是这种方法没有用在共享库中,主要是因为在应用程序执行之前链接器并不知道应用程序最终用到了库中的哪些部分。因此要对共享库进行裁剪必须先分析动态链接的原理。
共享库和可执行文件中都有若干个符号表,其中定义了一些外部符号,分为导出(export)符号和导入(import)符号这两种。导出符号是指在该文件中定义但可以被其它文件使用的符号,一般是可以由其它文件调用的函数;导入符号是指被该文件使用了但并没有定义的符号,一般是被该文件调用的函数,而且导入符号一般指明了定义该符号的共享库。加载器在加载可执行文件或共享库之前会先遍历它的每个导入符号,检查该符号的相关代码是否已在内存中,否则先查找并加载定义该符号的共享库。由于嵌入式Linux系统中的应用程序和共享库一般都是确定的,共享库中就可能存在永远不会被别的文件调用到的导出符号,将这些符号的相应代码从共享库中删除不会影响到系统的正常运行。
现有裁剪技术都是以上述原理实现的。下面则具体分析它的实现方法。
2.2、ELF文件符号提取
ELF格式是UNIX实验室作为应用程序二进制接口而开发和发布的,ELF是目前广泛应用于Linux系统中的一种文件格式。
2.2.1、 ELF文件进程映像加载
ELF文件开头部分是一个ELF Header结构,它包含两个指针,分别指向两个数组结构:Program header table和Section header
table,Program header table中的数组元素对文件内部的可执行代码段进行定位;Section header table中的数组元素保存相关重定位和动态链接信息.装载器通过控制这两类数组实现进程映像的加载。
上一篇:嵌入式系统中文输入法的设计