2009-08-22 13 views
13
test.c: 

int main() 
{ 
    return 0; 
} 

Non ho usato nessun bandiere (Io sono un newb a gcc), solo il comando:GCC: programma vuoto == 23202 byte?

gcc test.c 

ho usato l'ultima TDM build of GCC su win32. L'eseguibile risultante è quasi 23 KB, troppo grande per un programma vuoto.

Come posso ridurre la dimensione dell'eseguibile?

+0

Un suggerimento: ottieni gli stessi risultati utilizzando la versione minGW di GCC? Non sono sicuro che quella dimensione sia insolita o no, perché non sono molto abituato al C++. – Macha

+0

UPX? http://upx.sourceforge.net/ – bobince

+0

Sì, conosco UPX, ma il problema qui è questo: il compilatore non dovrebbe generare ~ 23KB di junk per un programma vuoto. – George

risposta

36

Non seguire i suoi suggerimenti, ma per amor di divertimento, leggere this 'story' su come rendere il più piccolo binario ELF possibile.

+6

+1 È una lettura divertente! –

+1

Merda, questo non doveva essere preso sul serio. Ora è la risposta più votata che ho dato! – Novelocrat

+1

Anche l'articolo collegato in http://stackoverflow.com/questions/553029/what-is-the-smallest-possible-windows-pe-executable è interessante. – bk1e

10

Per impostazione predefinita alcune librerie standard (ad esempio C runtime) collegate al file eseguibile. Controlla i tasti --nostdlib --nostartfiles --nodefaultlib per i dettagli. Opzioni di collegamento descritte here.

Per la seconda opzione del programma reale è provare optimization options, ad es. -Os (ottimizza per dimensione).

+0

Questo è corretto, ma in genere si _want_ quelle librerie. –

+0

Esatto. Queste chiavi che ho usato solo per i sistemi embedded. –

+0

Cosa mi consiglia di iniziare?(Sono nuovo di GCC, ma ho usato molto C in VisualCpp in precedenza) – George

21

Come è possibile ridurne le dimensioni?

  • Non pratico. Stai solo perdendo tempo.
  • Usa -s bandiera per mettere a nudo i simboli (GCC -s)
7

In realtà, se il codice non fa nulla, è anche giusto che il compilatore crea ancora un eseguibile? ;-)

Bene, su Windows qualsiasi eseguibile avrebbe comunque una dimensione, sebbene possa essere ragionevolmente piccola. Con il vecchio sistema MS-DOS, un'applicazione completa senza nulla sarebbe solo un paio di byte. (Penso che quattro byte utilizzino l'interruzione 21h per chiudere il programma.) Poi di nuovo, quelle applicazioni sono state caricate direttamente nella memoria. Quando il formato EXE divenne più popolare, le cose cambiarono un po '. Ora gli eseguibili avevano informazioni aggiuntive sul processo stesso, come il trasferimento del codice e dei segmenti di dati oltre ad alcuni checksum e informazioni sulla versione. L'introduzione di Windows ha aggiunto un'altra intestazione al formato, per indicare a MS-DOS che non è stato possibile eseguire l'eseguibile poiché era necessario eseguire Windows. E Windows lo riconoscerebbe senza problemi. Naturalmente, il formato eseguibile è stato esteso anche con informazioni sulle risorse, come bitmap, icone e moduli di dialogo e molto altro ancora.

Un eseguibile del nulla dovrebbe essere tra 4 e 8 kilobyte di dimensioni, a seconda del compilatore e di tutti i metodi utilizzati per ridurne le dimensioni. Sarebbe una dimensione in cui UPX risulterebbe in un eseguibile più grande! Potrebbero essere aggiunti ulteriori byte nel tuo eseguibile perché hai aggiunto alcune librerie al tuo codice. Specialmente le librerie con dati o risorse inizializzati aggiungono una quantità considerevole di byte. L'aggiunta di informazioni di debug aumenta anche la dimensione dell'eseguibile.

Ma anche se tutto questo è un buon esercizio per ridurre le dimensioni, ci si potrebbe chiedere se è pratico continuare a preoccuparsi di un eccesso di applicazioni. I dischi rigidi moderni divideranno i file in segmenti e per dischi molto grandi, la differenza sarebbe molto piccola. Tuttavia, la quantità di problemi che occorrerebbe per mantenere la dimensione più piccola possibile rallenterà la velocità di sviluppo, a meno che tu non sia uno sviluppatore esperto che è abituato a queste ottimizzazioni. Questi tipi di ottimizzazioni non tendono a migliorare le prestazioni e, considerando lo spazio medio su disco della maggior parte dei sistemi, non vedo perché sarebbe pratico. (Ancora, ottimizzo il mio codice in modo simile ma, di nuovo, sono esperto di queste ottimizzazioni.)


Interessato allo EXE header? Inizia con le lettere MZ, per "Mark Zbikowski".La prima parte è l'intestazione MS-DOS vecchio stile per i file eseguibili e viene utilizzata come stub per MS-DOS che indica che il programma è non un file eseguibile MS-DOS. (Nel file binario, è possibile trovare il testo "Questo programma non può essere eseguito in modalità DOS." Che è fondamentalmente tutto ciò che fa: visualizzare quel messaggio. Avanti è l'intestazione PE, che Windows riconoscerà e utilizzerà al posto di MS-DOS intestazione Inizia con le lettere PE for Portable Executable. Dopo questa seconda intestazione ci sarà l'eseguibile stesso, diviso in diversi blocchi di codice e dati.L'intestazione contiene speciali tabelle di riallocazione che indicano al sistema operativo in cui caricare un blocco specifico. mantenere ad un limite, l'eseguibile finale può essere inferiore a 4 KB, ma il 90% sarebbe allora le informazioni di intestazione e alcuna funzionalità.

+3

Come per un'applicazione DOS, un semplice ret farà. Cioè, 1 byte. –

+0

Un ret farebbe, ma la regola ufficiale era che dovevi chiamare l'interruzione "Esci". –

+0

Ho creato veri eseguibili di Windows (formato PE) che fanno cose utili in <4KB, usando VS2005. Quindi un eseguibile do-nothing non deve necessariamente essere 8KB. (Perché? Controllo automatico per un CD, non avviare un EXE di installazione di grandi dimensioni se l'app è già installata) – MSalters

2

Qual è lo scopo di questo esercizio?

Anche con il minimo livello linguaggio come C, c'è ancora un sacco di setup che devono succedere n prima che il main possa essere chiamato. Alcune di queste impostazioni sono gestite dal caricatore (che necessita di determinate informazioni), alcune sono gestite dal codice che chiama main. E poi c'è probabilmente un po 'di codice della libreria che qualsiasi programma normale dovrebbe avere. Per lo meno, ci sono probabilmente riferimenti alle librerie standard, se sono in dll.

L'esame della dimensione binaria del programma vuoto è un esercizio senza valore in sé e per sé. Non ti dice nulla. Se vuoi imparare qualcosa sulla dimensione del codice, prova a scrivere programmi non vuoti (e preferibilmente non banali). Confronta programmi che usano librerie standard con programmi che fanno tutto da soli.

Se vuoi davvero sapere cosa sta succedendo in quel file binario (e perché è così grande), allora scopri il formato eseguibile ottenere uno strumento di dump binario e separare la cosa.

+0

Dato che non si conoscono le motivazioni dell'OP, questo semplicemente non è vero. Potrebbe essere interessato ad entrare nello sviluppo embedded, dove le dimensioni del codice sono molto importanti, ad esempio. – Novelocrat

+3

La dimensione del codice del programma vuoto è ancora completamente irrilevante. E se è coinvolto in una programmazione embedded in cui la dimensione del programma è importante, qualsiasi cosa faccia scherzare con un compilatore di Windows è irrilevante. –

+0

La dimensione del codice di un programma vuoto non è irrilevante quando 1. si codificano le demo, 2. si è interessati a come funziona la compilazione, cosa finisce nell'eseguibile finale, 3. e infine quando si sa che un programma vuoto non dovrebbe essere ~ 23KB. Potrebbero non esserci usi ovvi di qualcosa di simile, ma non rende irrilevante l'apprendimento delle flag del compilatore. – George

3

Mi piace il modo in cui la FAQ DJGPP addressed this molti molti anni fa:

In generale, a giudicare dimensioni di codici, cercando nella dimensione dei programmi "Hello" non ha senso, perché tali programmi consistono in gran parte della startup codice. ... La maggior parte della potenza di tutte queste funzionalità va sprecata nei programmi "Ciao". Non ha senso eseguire tutto quel codice solo per stampare una stringa da 15 byte ed uscire.

+1

L'intero punto del programma vuoto è vedere l'overhead. Sono semplicemente interessato a come funziona la compilazione, cosa finisce in un binario compilato a parte il codice che ho inserito. – George

+2

Richard, non è affatto quello che hai chiesto nella tua domanda. Hai chiesto come sbarazzarti del sovraccarico. Non hai chiesto in che consistesse il sovraccarico. –

0

Utilizzando GCC, compilare il programma utilizzando -Os piuttosto che uno degli altri flag di ottimizzazione (-O2 o -O3). Questo dice di ottimizzare per dimensioni piuttosto che velocità. Per inciso, a volte può rendere i programmi più veloci rispetto alle ottimizzazioni della velocità, se qualche segmento critico dovesse adattarsi meglio. D'altra parte, -O3 può effettivamente indurre aumenti della dimensione del codice.

Potrebbero esserci anche alcuni flag di linker che dicono di lasciare codice inutilizzato dal binario finale.

+0

-Os non fa differenza con questo codice. –

+1

Non sorprende, in questo caso. Non c'è molto codice che GCC stia realmente toccando qui. – Novelocrat

11

Rinuncia. Su Linux x86, gcc 4.3.2 produce un binario 5K. Ma aspetta! Questo è con il collegamento dinamico! Il file binario staticamente collegato a supera il mezzo meg: 516K. Rilassati e impara a vivere con il peso.

E hanno detto che Modula-3 non andrebbe mai da nessuna parte a causa di un mondo binario da 200K ciao!


Nel caso in cui si chiedono cosa sta succedendo, la libreria GNU C è strutturata in modo da includere alcune funzioni se il programma dipende da loro o no. Queste caratteristiche includono trivia come malloc e free, dlopen, alcune string processing e un intero carico di carico di che sembra avere a che fare con localizzazione e internazionalizzazione, anche se non riesco a trovare pagine man pertinenti.

Creazione di piccoli eseguibili per i programmi che richiedono servizi minimi è non un obiettivo di progettazione per glibc. Per essere onesti, è stato anche non un obiettivo di progettazione per ogni sistema run-time con cui ho mai lavorato (circa una mezza dozzina).

1

Esegui la striscia sul binario per eliminare i simboli. Con gcc versione 3.4.4 (cygming speciale) scendo da 10k a 4K.

È possibile provare a collegare un tempo di esecuzione personalizzato (la parte che chiama principale) per impostare l'ambiente di runtime. Tutti i programmi usano lo stesso per configurare l'ambiente di runtime fornito con gcc, ma per il tuo eseguibile non hai bisogno di dati o di memoria azzerata. Ciò significa che è possibile eliminare le funzioni di libreria non utilizzate come memset/memcpy e ridurre le dimensioni CRT0. Quando cerchi informazioni su questo aspetto di GCC in ambiente embedded. Gli sviluppatori incorporati sono in genere le uniche persone che utilizzano ambienti di runtime personalizzati.

Il resto è overheads per il sistema operativo che carica l'eseguibile. Non andrai ugualmente là se non lo sintonizzi a mano?

2

Che cosa indica "size a.out" sulla dimensione dei segmenti di codice, dati e bss? La maggior parte del codice è probabilmente il codice di avvio (classicamente crt0.o su macchine Unix) che viene invocato dall'o/se imposta il lavoro (come l'ordinamento degli argomenti della riga di comando in argc, argv) prima di richiamare main().

Problemi correlati