Domanda

Sto producendo un file esadecimale da eseguire su un processore ARM che voglio mantenere sotto i 32 KB. Attualmente è molto più grande di così e mi chiedevo se qualcuno potesse avere qualche consiglio su quale sia l'approccio migliore per ridurlo?

Ecco cosa ho fatto finora

  1. Quindi ho eseguito 'size' su di esso per determinare quanto è grande il file hex.
  2. Quindi 'ridimensiona' di nuovo per vedere quanto è grande ciascuno dei file oggetto quel link per creare i file esadecimali. Sembra che la maggior parte delle dimensioni provenga da librerie esterne.
  3. Quindi ho usato 'readelf' per vedere quali funzioni occupano più memoria.
  4. Ho cercato nel codice per vedere se potevo eliminare le chiamate a quelle funzioni.

Ecco dove rimango bloccato, ci sono alcune funzioni che non chiamo direttamente (es. _vfprintf) e non riesco a trovare le chiamate così posso rimuovere la chiamata (poiché penso di non averne bisogno).

Quindi quali sono i prossimi passi?

Risposta alle risposte:

  • Come posso vedere ci sono funzioni chiamate che occupano molta memoria. Non riesco comunque a trovare ciò che lo chiama.
  • Voglio omettere quelle funzioni (se possibile) ma non riesco a trovare ciò che le chiama! Potrei essere chiamato da qualsiasi numero di funzioni di libreria credo.
  • Il linker funziona come desiderato, penso, include solo i file di libreria pertinenti. Come fai a sapere se vengono incluse solo le funzioni pertinenti? Puoi impostare una bandiera o qualcosa del genere?
  • Sto usando GCC
È stato utile?

Soluzione

Elenco generale:

  • Assicurati di aver disabilitato le opzioni di debug del compilatore e del linker
  • Compila e collega con tutte le opzioni di dimensione attivate (-Os in gcc)
  • Esegui strip sull'eseguibile
  • Genera un file mappa e controlla le dimensioni della tua funzione. Puoi ottenere il tuo linker per generare il tuo file di mappa ( -M quando usi ld), oppure puoi usare objdump sull'eseguibile finale (nota che funzionerà solo su un eseguibile non estratto!) in realtà risolverà il problema, ma ti farà conoscere i peggiori trasgressori.
  • Usa nm per investigare i simboli chiamati da ciascuno dei tuoi file oggetto. Questo dovrebbe aiutare a trovare chi chiama funzioni che non si desidera chiamare.

Nella domanda originale c'era una sotto-domanda sull'inclusione delle sole funzioni rilevanti. gcc includerà tutte le funzioni all'interno di ogni file oggetto utilizzato. Per dirlo in altro modo, se si dispone di un file oggetto che contiene 10 funzioni, tutte le 10 funzioni sono incluse nell'eseguibile anche se viene effettivamente chiamato 1.

Le librerie standard (es. libc) suddividono le funzioni in molti file di oggetti separati, che vengono quindi archiviati. L'eseguibile viene quindi collegato all'archivio. Suddividendo in molti file oggetto, il linker è in grado di includere solo le funzioni effettivamente chiamate. (questo presuppone che tu stia collegando staticamente)

Non c'è motivo per cui non puoi fare lo stesso trucco. Naturalmente, si potrebbe sostenere che se le funzioni non vengono chiamate è possibile rimuoverle da soli.

Se si esegue il collegamento statico con altre librerie, è possibile eseguire anche gli strumenti sopra elencati per assicurarsi che seguano regole simili.

Altri suggerimenti

Un'altra ottimizzazione che potrebbe farti risparmiare lavoro è -ffunction-sezioni, -Wl, - gc-sezioni, supponendo che tu stia utilizzando GCC. Tuttavia, non sarà necessario dirlo a una buona toolchain.

Spiegazione: GNU ld collega sezioni e GCC emette una sezione per unità di traduzione, salvo diversa indicazione. Ma in C ++, i nodi nel grafico della dipendenza sono oggetti e funzioni.

Solo per ricontrollare e documentare per riferimento futuro, ma usi le istruzioni Thumb? Sono versioni a 16 bit delle normali istruzioni. A volte potresti aver bisogno di 2 istruzioni a 16 bit, quindi non risparmierà il 50% nello spazio del codice.

Un linker decente dovrebbe prendere solo le funzioni necessarie. Tuttavia, potresti aver bisogno di compilatore e amp; linke settings per raggruppare le funzioni per i singoli collegamenti.

Su progetti profondamente integrati cerco sempre di evitare qualsiasi funzione di libreria standard. Anche funzioni semplici come " strtol () " esplodere la dimensione binaria. Se possibile, evita semplicemente quelle chiamate.

Nei progetti maggiormente integrati non è necessario un versatile " printf () " o allocazione dinamica della memoria (molti controller hanno 32kb o meno RAM).

Invece di usare solo " printf () " Uso una personalizzazione molto semplice "printf ()", questa funzione può solo stampare numeri in formato esadecimale o decimale, non di più. La maggior parte delle strutture di dati sono preallocate al momento della compilazione.

Ok, quindi alla fine ho appena ridotto il progetto nella sua forma più semplice, quindi ho aggiunto lentamente i file uno per uno fino a quando la funzione che volevo rimuovere appariva nel file 'readelf'. Poi, quando ho avuto il file, ho commentato tutto e aggiunto lentamente le cose fino a quando la funzione non è comparsa di nuovo. Quindi alla fine ho scoperto come lo chiamava e ho rimosso tutte quelle chiamate ... Ora funziona come desiderato ... dolce!

Tuttavia deve essere un modo migliore per farlo.

Andrew EdgeCombe ha un ottimo elenco, ma se vuoi davvero grattare ogni ultimo byte, sstrip è un buon strumento che manca dall'elenco e può radere qualche altro kB.

Ad esempio, quando eseguito su strip stesso, può radersi ~ 2kB .

Da un vecchio README (vedi i commenti nella parte superiore di questo file sorgente indiretto):

  

sstrip è una piccola utility che rimuove il contenuto alla fine di un   File ELF che non fanno parte dell'immagine di memoria del programma.

     

La maggior parte degli eseguibili ELF sono creati sia con una tabella di intestazione del programma che a   tabella delle intestazioni di sezione. Tuttavia, solo il primo è richiesto in ordine   affinché il sistema operativo carichi, colleghi ed esegua un programma. sstrip tenta di   estrarre l'intestazione ELF, la tabella di intestazione del programma e il suo contenuto,   lasciando tutto il resto nel secchio bit. Può rimuovere solo parti di   il file che si presenta alla fine, dopo le parti da salvare. Però,   questo include quasi sempre la tabella delle intestazioni di sezione, e occasionalmente   alcune sezioni casuali che non vengono utilizzate durante l'esecuzione di un programma.

Si noti che a causa di alcune delle informazioni che rimuove, un eseguibile con striping è si dice che abbia problemi con alcuni strumenti. Questo è discusso di più nei commenti della fonte.

Inoltre ... per una lettura divertente / folle su come rendere il più piccolo eseguibile possibile, questo articolo merita una lettura.

Per rispondere a questa esigenza specifica:

  

• Voglio omettere quelle funzioni (se possibile) ma non riesco a trovare cosa   chiamandoli !! Potrebbe essere chiamato da qualsiasi numero di funzioni di libreria I   indovinare.

Se vuoi analizzare la tua base di codice per vedere chi chiama cosa, da chi viene chiamata una determinata funzione e cose del genere, c'è un ottimo strumento là fuori chiamato " Capisci C " fornito da SciTools.

https://scitools.com/

L'ho usato molto spesso in passato per eseguire analisi di codice statico. Può davvero aiutare a determinare l'albero delle dipendenze delle librerie. Permette di navigare facilmente su e giù nella struttura della chiamata, tra le altre cose.

Forniscono una valutazione a tempo limitato, quindi è necessario acquistare una licenza.

Potresti guardare qualcosa come compressione eseguibile .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top