Linux 可执行程序打压缩

对于设计嵌入式Linux系统的研发人员来说,有一个问题是必须要考虑到的,那就是存储器的空间。
我们知道嵌入式Linux系统所用的存储器不是软磁盘、硬盘、ZIP盘、CD-ROM、DVD这些众所周知的大容量常规存储器,它使用的是例如Rom, CompactFlash,M-Systems的DiskOnChip,SONY的MemoryStick,IBM 的MicroDrive等体积极小,与主板上的BIOS大小相近,存储容量很小的存储器。所以怎样尽可能的节省空间就显的很重要。
嵌入式系统的存储器中放置的无非是内核,文件系统,软件,以及自己开发的程序。本文就从程序入手,以一个非常简单的C程序来作为例子,通过三步来让它减肥。

  1. //Hello.c:
  2. #include
  3. int main ( )
  4. {
  5.     printf ( "hello,world" ) ;
  6.     return 0 ;
  7. }

我们先用正常的编译方法来编译,看看生成的程序的大小是多少

#gcc –o hello hello.c
#ls –l hello
-rwxr -xr -x 1 root root 11542 Nov 13 20 : 07 hello

从结果可以看到正常编译后的程序大小是11542Byte, 现在开始我们的三步减肥,看看到底效果如何。

步骤一:用gcc 的代码优化参数

代码优化指的是编译器通过分析源代码,找出其中尚未达到最优的部分,然后对其重新进行组合,目的是改善程序的执行性能。GCC提供的代码优化功能非常强大, 它通过编译选项-On来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的GCC来讲,n的取值范围及其对应的优化效果可能并不完全相同,比较典型的范围是从0变化到2或3。
编译时使用选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。选项-O3则除了完 成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越 快。许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。

#gcc –O2 –o hello hello.c
#ls –l hello
-rwxr -xr -x 1 root root 11534 Nov 13 20 : 09 hello

优化过的程序的大小是11534Byte,比正常编译的结果11542Byte似乎没有小多少,不过不用着急,这才是第一步。我们接着往下进行。

步骤二:用strip 命令

我们知道二进制的程序中包含了大量的符号信息(symbol table),有一部分是用来为gdb除错提供必要帮助的。可以通过readelf –S查看到这些符号信息。

#readelf -S hello
Section Headers :
[Nr ] Name Type
[ 0 ] NULL
[ 1 ] .interp PROGBITS
[ 2 ] .note .ABI -tag NOTE
[ 3 ] . hash HASH
[ 4 ] .dynsym DYNSYM
[ 5 ] .dynstr STRTAB
[ 6 ] .gnu .version VERSYM
[ 7 ] .gnu .version_r VERNEED
[ 8 ] .rel .dyn REL
[ 9 ] .rel .plt REL
[ 10 ] .init PROGBITS
[ 11 ] .plt PROGBITS
[ 12 ] .text PROGBITS
[ 13 ] .fini PROGBITS
[ 14 ] .rodata PROGBITS
[ 15 ] .eh_frame PROGBITS
[ 16 ] .data PROGBITS
[ 17 ] .dynamic DYNAMIC
[ 18 ] .ctors PROGBITS
[ 19 ] .dtors PROGBITS
[ 20 ] .jcr PROGBITS
[ 21 ] .got PROGBITS
[ 22 ] .bss NOBITS
[ 23 ] .comment PROGBITS
[ 24 ] .debug_aranges PROGBITS
[ 25 ] .debug_pubnames PROGBITS
[ 26 ] .debug_info PROGBITS
[ 27 ] .debug_abbrev PROGBITS
[ 28 ] .debug_line PROGBITS
[ 29 ] .debug_frame PROGBITS
[ 30 ] .debug_str PROGBITS
[ 31 ] .shstrtab STRTAB
[ 32 ] .symtab SYMTAB
[ 33 ] .strtab STRTAB

类似于.debug_xxxx的就是用来gdb除错的。去掉它们不但不会影响程序的执行还可以减小程序的size。这里我们通过strip命令拿掉它们。

#strip hello
#ls –l hello
-rwxr -xr -x 1 root root 2776 Nov 13 20 : 11 hello

程序立刻变成2776Byte了,效果不错吧。让我们再接再厉,进行最后一步。

步骤三:用objcopy 命令

上一步的strip命令只能拿掉一般symbol table,有些信息还是没拿掉,而这些信息对于程序的最终执行是没有什幺影响的。如:.comment; .note.ABI-tag; .gnu.version就是完全可以去掉的。所以说程序还有简化的余地,我们可以使用objcopy命令把它们抽取掉。

#objcopy –R .comment –R .note.ABI-tag –R .gnu.version hello hello1
#ls –l hello1
-rwxr -xr -x 1 root root 2316 Nov 13 20 : 23 hello1

到这一步,程序的减肥就完成了,我们可以看到程序由正常编译的11542Byte 一下子渐少到2316Byte,效果非常明显。

你可能感兴趣的:(Linux 可执行程序打压缩)