對於設計嵌入式Linux系統的研發人員來說,有一個問題是必須要考慮到的,那就是儲存空間的空間。
我們知道嵌入式Linux系統所用的儲存空間不是軟磁碟、硬碟、ZIP盤、CD-ROM、DVD這些眾所周知的大容量常規儲存空間,它使用的是例如Rom,CompactFlash,M-Systems的DiskOnChip,SONY的MemoryStick,IBM 的MicroDrive等體積極小,與主板上的BIOS大小相近,儲存容量很小的儲存空間。所以怎樣儘可能的節省空間的就顯的很重要。
嵌入式系統的儲存空間中放置的無非是核心,檔案系統,軟體,以及自己開發的程式。本文就從程式入手,以一個非常簡單的C程式來作為例子,通過三步來讓它減肥。
Hello.c:
#include
int main ()
{
printf ("hello,world");
return 0;
}
我們先用正常的編譯方法來編譯,看看產生的程式的大小是多少
#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系統的設計有著重要的意義,它為我們節省了大量空間,使得我們可以利用這部分空間來完善我們的系統,比如加大核心等等,畢竟這才是我們最終的目的。
作者簡介
姓名:雷凱
工作單位:升技主板(蘇州)研發中心
聯絡地址:蘇州市新區馬運路羅禮科技有限公司研發中心 郵編 215000
E-mail: tigerleihm@yahoo.com.cn
“本文作者是雷凱 升技主板(蘇州)研發中心工程師。他目前在中國蘇州 升技主板(蘇州)研發中心工作。可以通過tigerleihm@yahoo.com.cn 與他聯絡。”