鎖定9小時。對此問題的評論已被禁用,但它仍在接受新的答案和其他互動。了解更多。
考慮以下程式:
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
如果我使用 GCC 構建它,優化大小并使用靜態鏈接,然后剝離它以進一步減小大小(也許):
$ gcc -Os -static hello.c -o hello
$ strip hello
我得到一個大小約為 695 KB 的可執行檔案。
為什么這么大?我意識到這不僅僅是我的目標代碼,還有存根等等,但仍然是巨大的。
筆記:
- 作業系統:Devuan GNU/Linux Chimaera (~= Debian Bullseye)
- 編譯器:GCC 10.2
- 庫:glibc 2.31-13
- 處理器架構:x86_64
- 如果我用
-O3 -flto.
uj5u.com熱心網友回復:
部分答案:可執行檔案的膨脹大小......
- 與您的使用沒有任何
printf關系。 - 與編譯器優化代碼的能力沒有任何關系。
- 與您包含.沒有任何
<stdio.h>關系。
為什么?因為即使你編譯一個空程式:
int main(void)
{
return 0;
}
您仍然可以獲得相同的 695 KB 可執行檔案。
感謝@SparKot 指出這個方向的評論。
uj5u.com熱心網友回復:
從根本上說,這里的問題是 GNU libc 不是為靜態鏈接而設計的,這意味著開發人員沒有花任何時間來減少靜態鏈接二進制檔案的大小。
我用-static特殊的編譯器引數編譯了你的程式,-Wl,-Map,a.map它要求聯結器寫出一個檔案a.map(你可以在該咒語中的第二個逗號之后放置你喜歡的任何名稱),它解釋了為什么每個目標檔案都包含在鏈接中。這些是該檔案的前幾行,為了便于閱讀,稍作編輯:
Archive member included to satisfy reference by file (symbol)
/usr/lib/libc.a(libc-start.o)
/usr/lib/crt1.o (__libc_start_main)
/usr/lib/libc.a(check_fds.o)
/usr/lib/libc.a(libc-start.o) (__libc_check_standard_fds)
/usr/lib/libc.a(libc-tls.o)
/usr/lib/libc.a(libc-start.o) (__libc_setup_tls)
/usr/lib/libc.a(errno.o)
/usr/lib/libc.a(check_fds.o) (__libc_errno)
/usr/lib/libc.a(assert.o)
/usr/lib/libc.a(libc-start.o) (__assert_fail)
/usr/lib/libc.a(dcgettext.o)
/usr/lib/libc.a(assert.o) (__dcgettext)
這意味著在聯結器甚至查看程式代碼之前,當它仍在處理呼叫 main函式的傳遞依賴時,它需要拉入列印斷言失敗訊息的代碼,并且該代碼拉入用于動態加載和列印本地化(翻譯成用戶的母語)錯誤訊息的代碼。看起來您的 600K 二進制可執行檔案的大部分是代碼及其依賴項,其中包括 all of malloc、 all of fprintf、 all of 、 “訊息物件”檔案iconv的決議器,...gettext
uj5u.com熱心網友回復:
為什么-static在編譯代碼時使用?
您將代碼編譯為靜態可執行檔案,因此它從 鏈接所有庫(例如 stdio)libc.a,提取使用的模塊并將它們鏈接到程式代碼中,而不是從鏈接libc.so。 printf()(以及許多標準函式)不幸的是,它是一個復雜的例程,它處理輸入/輸出的緩沖,并且當您必須在程式中包含代碼時使您的可執行檔案變得更大。
另一方面,如果您允許聯結器進行動態鏈接,您將獲得大約 16 kb 的動態可執行檔案并且無需額外的加載作業,因為 libc 始終為您在系統記憶體中預加載(因為幾乎每個程式都使用它,因此它會在系統中動態鏈接的第一個程式啟動時立即加載 - 例如systemd或init)。如果它是共享物件,內核不需要加載標準庫,因為它通常在程式啟動時已經加載。靜態鏈接程式時不會發生這種情況。庫的使用代碼包含在您的可執行檔案中,但由于它沒有共享代碼......必須將完整的兆位元組從可執行檔案加載到記憶體中,并在性能上加載啟動懲罰。
您仍然可以在該大小以下,但為此您必須在匯編程式中完成,而不是鏈接標準 c 庫和運行時模塊。
下一個程式,在匯編程式中,減少到 8488 位元組。除了使用的代碼僅是以下位元組(反匯編后)其余用于 ELF 合規性(默認重定位表等)
401000: b8 04 00 00 00 mov $0x4,
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/456851.html
上一篇:我想從C語言的檔案中獲取雙精度值
