2011-07-21 128 views
12

我知道有一個選項「-Os」爲「優化尺寸」,但它幾乎沒有影響,甚至在某些場合增加了尺寸:(如何減少生成的二進制文件的大小?

strip(或「-s」選項)調試符號表,工作正常;?但它只能減少只大小的小propotion

有沒有別的路可走furthur

+0

是什麼讓你覺得它太大? – bdonlan

+3

在一些嵌入式設備上,例如運行openwrt的路由器,只有4MB閃存... – felix021

回答

10

除了顯而易見的(-Os -s)之外,將函數對齊到不會崩潰的最小可能值(我不知道ARM對齊要求)可能會擠出每個函數的幾個字節。
-Os應該已經禁用了對齊功能,但是這可能仍然默認爲像4或8那樣的值。使用ARM可能爲1,這可能會節省一些字節。

-ffast-math(或磨損較小的-fno-math-errno)不會設置errno並避免一些檢查,從而減少代碼大小。如果像大多數人一樣,你不讀errno,那是一個選擇。

正確使用__restrict(或restrict)和const可消除冗餘負載,使代碼更快更小(更正確)。正確地標記純函數就能夠調用函數調用。

啓用LTO可能會有幫助,如果不可用,編譯所有的源文件轉換成二進制一氣呵成(gcc foo.c bar.c baz.c -o program,而不是編譯foo.cbar.c,並baz.c先,然後鏈接目標文件),將產生類似的效果。它使優化器一次都可見,可能使其更好地工作。 (請注意,這通常在嵌入式目標上啓用「O」,但是而不是)。

把靜態全局變量(你希望沒有那麼多,但仍然)放入一個結構體可以使大量的開銷初始化它們。我瞭解到,在編寫我的第一個OpenGL加載器時。讓一個結構中的所有函數指針和初始化結構爲= {}生成一個調用memset,而初始化指針「正常的方式」生成一個百千字節的代碼,只是爲了設置每個零個別。

避免非平凡構造函數靜態本地變量像魔鬼(POD類型沒有問題)。除非你用-fno-threadsafe-statics進行編譯,否則Gcc會初始化非平凡構造函數的靜態局部線程安全,除非你編譯了很多的額外代碼(即使你根本不使用線程)。

使用類似libowfat而不是正常的crt可以大大減少你的二進制大小

5

假設其他工具也允許;-)

然後考慮使用運行時解壓縮的UPX: the Ultimate Packer for Binaries

快樂編碼。

+0

非常感謝......我以爲這只是Windows ... – felix021

+2

請注意,這可能會增加RAM消耗,尤其是在共享庫上使用時。 – bdonlan

+0

它使交換效率降低。當交換從ELF二進制映射的頁面時,它只是丟棄頁面的內容,而不必將頁面寫入交換文件。當頁面沒有文件映射時,它必須首先將頁面保存到交換文件。 –

6

You can also use-nostartfiles和/或-nodefaultlibs或兩者-nostdlib的組合。如果你不想要一個標準的開始文件,那麼你必須編寫你自己的_start函數。還this thread參見ompf

(引用睿)

# man syscalls 
# cat phat.cc 
extern "C" void _start() { 
     asm("int $0x80" :: "a"(1), "b"(42)); 
} 
# g++ -fno-exceptions -Os -c phat.cc 
# objdump -d phat.o 

phat.o:  file format elf64-x86-64 

Disassembly of section .text: 

0000000000000000 <_start>: 
    0: 53      push %rbx 
    1: b8 01 00 00 00   mov $0x1,%eax 
    6: bb 2a 00 00 00   mov $0x2a,%ebx 
    b: cd 80     int $0x80 
    d: 5b      pop %rbx 
    e: c3      retq 
# ld -nostdlib -nostartfiles phat.o -o phat 
# sstrip phat 
# ls -l phat 
-rwxr-xr-x 1 tbp src 294 2007-04-11 22:47 phat 
# ./phat; echo $? 
42 

總結:以上片斷產生的294字節,每個字節8個比特的二進制。

+1

謝謝,你給了我生命,宇宙和一切的答案,哈哈。 – felix021

4

它也取決於您使用的架構。

您可以使用Thumb指令集來減少生成的代碼大小。

您也可以避免動態鏈接,並且希望靜態鏈接僅用於程序使用的庫或系統上很少的程序。這不會減少您生成的二進制本身的大小,但總的來說,您將在此程序的系統上佔用較少的空間。

2

當使用(1)時,您需要確保使用所有相關選項。出於某種原因,--strip-all並不總是剝奪一切。刪除不必要的部分可能會有所幫助。

但是,最終減少二進制文件大小的最好方法是從程序中刪除代碼和靜態數據。讓它少做,或選擇編程結構,導致更少的指令。例如,您可以在運行時構建數據結構,或根據需要從文件加載它們,而不是使用靜態初始化的數組。

+0

謝謝,非常實用的解決方案^ ^。 – felix021

2

你可以嘗試玩-fdata-sections,-ffunction-sections-Wl,--gc-sections,但這不是安全的,所以一定要在使用它們之前瞭解它們是如何工作的。