2016-04-16 9 views
-1

Kürzlich erkannte ich, dass die Größe meiner ausführbaren Dateien ziemlich groß ist. Ich entwickle Software für Cortex-M-Mikrocontroller mit Eclipse und GCC.Die Kartendatei verstehen, für die Größe optimieren

Um dies zu überprüfen, habe ich ein Beispielprojekt verwendet, das ich im Internet gefunden habe, das einfach eine LED blinkt, indem man die Register direkt manipuliert und das ist Makefile basiert.

Ich erstellte ein sehr ähnliches Projekt mit meinen Bibliotheken, Startup-Code, Linker-Skripten usw., die Eclipse verwaltete Makefiles verwendet.

Das erste Projekt erfolgreich kompiliert und eine binäre Datei der App erstellt. 6kB. Das zweite Projekt produzierte eine Binärdatei von ca. 48kB! Das ist offensichtlich ein ziemlich großer Unterschied für im Wesentlichen das gleiche Ergebnis, und das spätere ist definitiv eine riesige Datei, nur um eine LED zu blinken. In beiden Fällen waren Optimierungen aus.

In meinen eigenen Bibliotheken gibt es einige flüchtige Puffer, die die Entschuldigung für die großen BSS- oder Datenabschnitte sein können, also entschied ich mich, mich auf den Textabschnitt zu konzentrieren (der immer noch 5 mal größer ist als 5kB)).

Ich schaute mir die Map-Datei an, um zu sehen, was wirklich mit der Binärdatei verbunden ist. Gleiche oder ähnliche Funktionen hatten ebenfalls eine ähnliche Größe.

Es gibt eine Sache, die mir sehr seltsam erscheint. Es gibt Funktionen, die nur einmal im gesamten Projekt definiert sind, aber scheinbar mehrfach verknüpft sind, jedes Mal aus einer anderen Objektdatei, und jedes Mal, wenn Platz im Textabschnitt belegt wird. Schauen Sie sich zum Beispiel die Funktion .text.port_lock an.

Ist das normal? Wie kann ich die endgültige Dateigröße reduzieren und wie kann ich der Toolchain mitteilen, dass sie nur einmal jede Funktion verknüpft?

The map file

Edit: Wie in den Kommentaren erklärte die beiden Programme nicht unterschiedlich sind, ist es dasselbe, mit geringfügigen Änderungen (zum Beispiel Startcode, und dazu dienen, das GPIO-Register zuzugreifen). Ich prüfe nicht die Fähigkeit von GCC, Code zu optimieren, also habe ich -O0 verwendet. Ich versuche, die Map-Datei zu verstehen, und warum sehe ich einige Funktionen mehrmals.

+0

So klar zu sein, Sie sagen, dass Sie die kompilierten Größen von zwei völlig getrennten und unabhängigen Programmen vergleichen, die die gleiche (einfache) Funktion ausführen? –

+0

GCC hat die Option '-Os', um für kleine ausführbare Dateien zu optimieren. Sie könnten darüber nachdenken, das einzuschalten. Oder sogar "-O1" könnte besser in der Größe sein als überhaupt keine Optimierung. Wie für mehrere Kopien der gleichen Funktion in dem ausführbaren Bild - wenn das tatsächlich das ist, was Sie sehen - haben Sie uns nicht viel gegeben, um weiterzumachen. Kannst du ein [mcve] produzieren, das das Problem zeigt? –

+0

Bewusst wurden die Optimierungen ausgeschaltet. Ich teste nicht die Fähigkeit des Compilers, Code zu optimieren. Ich untersuche, wie ich den Code optimieren kann. Die beiden Programme unterscheiden sich nicht. Sie sind die gleichen, mit einigen sehr kleinen Änderungen. Die Frage besteht darin, die Map-Datei zu verstehen und die gleiche Funktion mehrmals zu sehen. –

Antwort

1

Sie lesen die Map-Datei falsch. Keines der Vorkommen von .text.port_lock, zum Beispiel stellt eine Definition der ChibiOS-Funktion void port_lock(void) dar.

Alle Vorkommen von .text.port_lock beziehen sich auf Eingabe-Linkerabschnitte.

Die ersten 4 Vorkommen innerhalb des Abschnitts der Kartendatei Discarded input sections siehe Abschnitte Eingang Linker betitelte liegen, die der Linker verworfen. Zum Beispiel:

.text.port_lock 
       0x00000000  0x1c /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chmempools.o) 

bedeutet, dass der Linker einen Abschnitt .text.port_lock der Größe 28 Bytes in Eingabedatei /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chmempools.o) und warf es weg gefunden.

die nächsten 6 Vorkommen, im dem Abschnitt der Kartendatei Linker script and memory map alle Titel liegenden siehe Eingangslinkerabschnitte, die in den Ausgabe .text Abschnitt kartiert waren.Zum Beispiel kann die ersten:

.text.port_lock 
      0x000012a8  0x1c /tmp/ccaossic.ltrans0.ltrans.o 

bedeutet, dass der Linker einen Abschnitt .text.port_lock der Größe 28 Bytes in Eingabedatei /tmp/ccaossic.ltrans0.ltrans.o und kartiert sie bei der Adresse 0x000012a8 im Ausgabe .text Abschnitt. Ebenso ist die zweite Vorkommen:

.text.port_lock 
       0x00001f70  0x1c /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chsys.o) 

bedeutet, dass ein Eingangsabschnitt des gleichen Namens und Größe auch in der Eingabedatei /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chsys.o) und wurde bei der Adresse 0x00001f70 im Ausgabe .text Abschnitt kartiert wurde gefunden.

Insgesamt gibt es .text.port_lock Eingangsabschnitte, alle von ihnen 28 Bytes, in Ihrer Ausgabe .text Abschnitt aus diesen Eingabedateien zugeordnet:

/tmp/ccaossic.ltrans0.ltrans.o 
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chsys.o) 
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chthreads.o) 
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chcore_v7m.o) 
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chmemcore.o) 
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chschd.o) 

In allen sechs dieser Fälle der Eingabeabschnitt enthält keine Symbole und insbesondere keine Funktionen. Für Kontrast, hier ist ein Beispiel für einen Eingangsabschnitt, dass tun Symbole enthalten:

.text   0x000002f0  0x28 /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chcoreasm_v7m.o) 
       0x000002f0    _port_switch 
       0x00000300    _port_thread_start 
       0x00000310    _port_switch_from_isr 
       0x00000314    _port_exit_from_isr 

Dies ist der Eingang .text Abschnitt von /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chcoreasm_v7m.o).

Die Map-Datei enthält keinen Hinweis darauf, dass die Funktion port_lock mehrfach verknüpft ist. Es enthält keine Anzeige, dass diese Funktion überhaupt verknüpft ist. Wenn es mehrfach verknüpft wäre, dann wäre ein Mehrfachauflösungs-Verknüpfungsfehler gewesen (außer in dem Fall, dass es als weak symbol annotiert wurde).

Warum diese sechs 28-Byte-Eingabeabschnitte, die keine Symbole enthalten, alle verknüpft sind, oder ob sie sein müssen, ist eine Angelegenheit, über die ich keine ausreichenden Beweise oder ChibiOS-Kenntnisse habe. Ich bemerke , dass alle außer einer der Objektdateien, aus denen diese Eingabeabschnitte stammen, Archivmitglieder von libChibios sind. In diesem Licht lohnt es sich zu erinnern, dass, wenn Ihre Verknüpfung ein Archiv-Mitglied aus irgendeinem Grund erfordert, dann standardmäßig verknüpfen Sie die ganze Archiv-Mitglied, auch es enthält mehr Zeug als Sie brauchen. Auf der anderen Seite, die Tatsache , dass einige port_lock Eingabeabschnitte verworfen werden und einige beibehalten werden schlägt vor, dass es ist ein Bedarf, diejenigen zu halten, die gehalten werden. Wenn für meine eigenen listig Gründe, warum ich eine Quelldatei schreiben im Wesentlichen wie:

static int __attribute__((section(".text.foo"))) __attribute__((used)) 
boo(int i) 
{ 
    return i * 2; 
} 

int bar(int i) 
{ 
    return boo(i); 
} 

dann in meiner Map-Datei finden Sie einen leeren Eingabeabschnitt .text.foo genannt sehen. Diese sagt nichts über die Symbole, die ich verlinke.

Wie kann ich der Toolchain mitteilen, nur einmal jede Funktion zu verknüpfen?

Der Linker wird nicht Link Symboldefinition mehr als einmal, außer in dem speziellen bei schwachen Symbolen.Ihre Map-Datei enthält keine Hinweise darauf, dass eine Funktion mehr als einmal verknüpft ist.

Wie kann ich die endgültige Dateigröße reduzieren?

Kompilieren Sie mit -Os für Ihre Freigabe, natürlich. Um die Kopplungsredundanz zu minimieren, siehe , siehe this question.

Das Lesen einer Linker-Map-Datei ist normalerweise eine kluge Art, die Symbole und Abschnitte in Ihren Binärdateien zu untersuchen. Bevorzugen objdump, readelf und nm

+0

Das war sehr klar. Scheint, ich muss einen anderen Weg finden, um zu untersuchen, wie ich den Raum verschwende ... –

Verwandte Themen