Monday, April 11, 2011

Embedded中mkimage objcopy的Utilities.

  • mkimage:   (Ref: http://www.wretch.cc/blog/poemsoul/15441093, http://matttt-blog.blogspot.com/2010/01/mkimage.html, http://www.10pig.cn/bbs/showtopic.aspx?topicid=37703&page=end)

  mkimage這個工具為你的內核加上u-boot引導所需要的檔案頭(called uImage),具體做法如下︰
[root@localhost tftpboot]#mkimage -n 'linux- 2.6.14 ' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage zImage.img
 

Image Name: linux-2.6.14
Created: Fri Jan 12 17:14:50 2007
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1262504 Bytes = 1232.91 kB = 1.20 MB
Load Address: 0x30008000
Entry Point: 0x30008000


  
如上的作法即可產生u-boot載入時的訊息.因此在u-boot的命令列中執行tftp的動作並載入核心時,會產生如下訊息:
sbc2410=>tftp 0x31000000 zImage.img 

sbc2410=>bootm 0x31000000
 

## Booting image at 31000000 ...
Image Name: linun-2.6.14
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1263260 Bytes = 1.2 MB
Load Address: 30008000
Entry Point: 30008000
Verifying Checksum ... OK
OK

Starting kernel ...

  • objcopy (http://www.cmlab.csie.ntu.edu.tw/~daniel/linux/objcopy.html, http://blog.linux.org.tw/~jserv/archives/001767.html)
    copy and translate object files:
        * 複製 .o 檔 (obj file) 的內部內容到另一個檔案中 (.o 檔或是單純地做 hex dump)
        * 將一個 binary data (如JPEG 圖片) 做成 .o 檔
        * 把執行碼從 ELF 中抽取出來
        * 只抽取指定的 section 


Example 1:  將一個 JPEG 圖片檔 做成 .o 檔.
    $ objcopy -I binary -O elf32-i386 -B i386 image.jpg image.o
Example 2:  把執行碼從 ELF 中抽取出來,去除 symbol table, relocation information, .comment section, 和 .note section.
    $ objcopy -O binary -S -R .comment -R .note code.o code.bin
Example 3: 只抽取指定的 section.
    $ objcopy -O binary -j .text code.o code.bin


  • 程式減肥三步走 (http://linux.vbird.org/somepaper/20050117-jianfei.pdf)
    對於設計嵌入式 Linux 系統的研發人員來說,有一個問題是必須要考慮到的,那就是記憶體的空間。
我們知道嵌入式 Linux 系統所用的記憶體不是軟碟、硬碟、ZIP 盤、CD-ROM、DVD 這些? 所周知的大容量常規記憶體,它使用的是例如Rom,CompactFlash,M-Systems 的DiskOnChip,SONY 的MemoryStick,IBM 的MicroDrive 等體積極小,與主板上的BIOS大小相近,存儲容量很小的記憶體。所以怎樣盡可能的節省空間就顯的很重要。嵌入式系統的記憶體中放置的無非是內核,文件系 統,軟體,以及自己開發的程式。本文就從程式入手,以一個非常簡單的C 程式來作? 例子,通過三步來讓它減肥。
Hello.c:
    #include <stdio.h>
    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
  ...
  [10] .init PROGBITS
  ...
  [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,效果非常明顯。

No comments:

Post a Comment