Mir ist aufgefallen, dass der Linker nicht benutzte Funktionen trotzdem mit linkt und Speicherplatz belegt. Gibt es eine Möglichkeit diese Funktionen automatisch weg zu lassen? Ich weiß, das wurde vor Jahren schonmal diskutiert; ohne Ergebnis. Jetzt hoff ich einfach, dass sich da mittlerweile etwas getan hat :-) by(e) Stephan PS: ich verwende WinAVR-20090313
Der Linker kann i.d.R. nur ganze Objektdateien linken oder weglassen. Sobald auch nur ein Objekt (Funktion, globale Variable) aus einer Objektdatei benutzt wird, ist gleich alles andere aus dieser Datei auch dabei. Eine Optimierung würde also eine entsprechende Aufteilung auf kleinere Objektdateien voraussetzen.
-ffunction-sections -fdata-sections an den Compiler und --gc-sections an den Linker übergeben, damit sollten ungenutze Funktionen nicht mehr gelinkt werden. mfG Markus
Dem GNU Linker sagt man mit --gc-sections, dass er unbenutzte Sektionen rauswirft. Mit --print-gc-sections listet er die rausgeworfenen auch auf. Dem gcc kann man mit -ffunction-sections sagen, dass er jede Funktion in eine eigene Sektion legt, damit funktioniert das auch unterhalb der Ebene einer Quellcodedatei (also eine Funktion rausschmeissen obwohl fünf andere in derselben Datei gebraucht werden). Mit der Option -fdata-sections geht das auch für statische Variablen. Ob diese Optionen aber schon in den Versionen im WinAVR vorhanden sind weiß ich jetzt nicht.
Herzlichen Dank für eure Hilfe, jetzt hab ich wieder 10% mehr Speicher :-) Besonders der Tipp mit --print-gc-sections war sehr aufschlussreich. Mit den richtigen Schlagwörtern bewaffnet funktioniert auch die weitergehende Suche richtig gut. Ich hoffe ich trete jetzt keine Prinzipiendiskussion los, aber warum macht man das nicht gleich standardmäßig? tnx, Stephan
Vielleicht weil die meisten Systeme sowieso dynamische Libs unterstützen; dann ist das nicht mehr besonders relevant. Der gcc und seine Umgebung wird ja nur zu einem Bruchteil für AVR etc. verwendet.
Mit der Optimierung:
1 | --combine -fwhole-program |
werden auch alle nicht benutzten Funktionen gelöscht. Zusätzlich werden alle nur einmal aufgerufenen Funktionen geinlined. Man kann also ruhig modular und leserlich schreiben, es gibt keinen unnützen Call/Return Overhead. Auch werden volatile Sünden streng bestraft. Zusätzliche Init-Sektionen müssen aber als used deklariert werden. Peter
Peter Dannegger schrieb: > Mit der Optimierung:--combine -fwhole-program > werden auch alle nicht benutzten Funktionen gelöscht. Dafür müssen bei der Option aber alle sourcefiles in einem Aufruf übersetzt werden, das passt dann eher für kleinere Programme. Oliver
Stephan V. schrieb: > Ich hoffe ich trete jetzt keine Prinzipiendiskussion los, aber warum > macht man das nicht gleich standardmäßig? Weil es eigentlich von schlechtem Programmierstil zeugt, wenn man Dinge im Quellcode stehen hat, von denen man gar nicht weiß, dass man sie eigentlich gar nicht (mehr) braucht? Meiner Erinnerung nach ist die ganze Geschichte mit den function sections und dem gc-sections von der C++-Seite vorangetrieben worden: durch bestimmte Formalismen dieser Sprache ist der Compiler zuweilen gezwungen, Code zu emittieren, von dem noch nicht klar ist, ob er am Ende wirklich benutzt wird. Für diesen Code ist jedoch der Programmierer nicht selbst verantwortlich, folglich kann er das Dilemma (anders als du in deinem Code ;-) auch nicht abstellen, sodass die genannte Methode in diesem Falle die einzige ist, wie man den ungenutzten Code dann doch rauswerfen kann.
Stephan V. schrieb: > Ich hoffe ich trete jetzt keine Prinzipiendiskussion los, aber warum > macht man das nicht gleich standardmäßig? Das Verhalten ändert man nicht so einfach ohne guten Grund. Jede Funktion in eine eigene Sektion zu packen ist nun mal auch nicht Standard, und wenn das im Linkerscript nicht berücksichtigt wird funktioniert es auch nicht. Davon abgesehen kann es auch Sachen rausschmeissen, die nur anscheinend unbenutzt sind. Dazu ist es halt, wie auch in der Doku beschrieben, viel aufwendiger für den Linker oder/und den Lader. Die müssen jetzt mit dem Vielfachen an Sektionen arbeiten und haben entsprechend mehr Verwaltungsaufwand. Bei den Programmgrößen typisch für einen Mikrocontroller ist das beim Linken wohl kaum spürbar und einen Lader gibt es da auch nicht, da schon der Linker ein fertiges Image anfertigt. Also lässt es sich hier ganz gut nutzen.
Andreas B. schrieb: > Sektionen arbeiten und haben entsprechend mehr Verwaltungsaufwand. Bei > den Programmgrößen typisch für einen Mikrocontroller ist das beim Linken > wohl kaum spürbar Durchaus spürbar. Insbesondere wenn man I/O-Module für allerlei Periphieriekram hat und dort nicht jede einzelne Funktion in ein eigenes Quellfile packen will. Wenn man dann von solchen projektübergreifend gebauten Modulen nur ein Subset verwendet, dann macht sich das sehr wohl in der Grösse bemerkbar. Andererseits spielt der erhöhte Aufwand beim Übersetzen auf heutigen PCs keine nennenswerte Rolle mehr, wenn es um für Controller typische Programmgrössen geht.
Das mit schlechtem Programmierstil kann ich so nicht ganz gelten lassen. OK, wenn ich ein Programm habe, dass aus genau einem program.c besteht, dann hast du vollkommen recht, aber wenn mein Projekt aus mehreren Modulen, die auch noch in anderen Projekten wiederverwendet werden, besteht (=> siehe guter Stil), dann stimmt das so nicht mehr ganz. Das Ganze in eine Lib verpacken funktioniert bei Mikroprozessoren aufgrund der großen Anzahl an HW-Plattformen auch nicht wirklich, d.h. die Module kommen als Sourcen mit ins Projekt und sind tw. nichtmal selbst geschrieben / gewartet -> UART, LAN, ... (Hier mal ein großes Dankeschön an alle, die diese Sourcen bereitstellen und sich darum kümmern!) Alle Argumente die ich bis jetzt gehört habe treffen auf wirklich große PC Projekte zu. Und der GCC ist nun mal ein allgemeiner Compiler und nicht speziell für Mikroprozessoren, soviel ist auch klar. Aber, wenn ich jetzt in erster Linie mal an (größere) Mikroprozessorprojekte denkt, gibt es hier einen Nachteil dieser Optimierung auf den ich achten muss? Das Funktionen bzw. Sections "versehentlich" wegoptimiert werden (Stichwort Interrupt-Tabellen) hab ich schon gelesen, dass ist aber durch die neuen Link-Skripts schon automatisch abgefangen. Wie kann dies in meinem eigenen Code auftreten?
Stephan V. schrieb: > aber wenn mein Projekt aus mehreren > Modulen, die auch noch in anderen Projekten wiederverwendet werden, > besteht (=> siehe guter Stil), dann stimmt das so nicht mehr ganz. Pack' einen "logischen Block" (also alle Funktionen und Daten, die logisch zu einer bestimmten Funktionalität gehören) in je eine Datei. Daraus compilierst du zusammen mit dem Programm zuerst eine Bibliothek, und aus der nimmt sich der Linker nur die Objektmodule, die er auch wirklich braucht (diese aber jeweils komplett).
Stephan V. schrieb: > Das Funktionen bzw. Sections "versehentlich" wegoptimiert werden > (Stichwort Interrupt-Tabellen) hab ich schon gelesen, dass ist aber > durch die neuen Link-Skripts schon automatisch abgefangen. Wie kann dies > in meinem eigenen Code auftreten? Beispielsweise wird bei Cortexen die Vektorleiste gern auf vordefinierte Dummies geleitet, die als "weak externals" gekennzeichnet sind. Der User kann diese durch eigene Handler überstimmen. Nur sieht der Linker keinen Anlass, extra dafür eine sonst nicht benötigte Funktion als notwendig zu erkennen.
Oliver schrieb: > Dafür müssen bei der Option aber alle sourcefiles in einem Aufruf > übersetzt werden, das passt dann eher für kleinere Programme. AVR-Programme sind ja im Vergleich zu PC-Programmen immer klein (<256kB). Mir ist jedenfalls bisher noch keine störende Compilierzeit aufgefallen. Ich compiliere in der Regel sogar auf dem Netzlaufwerk, weils trotzdem schnell genug geht. Was man dagegen deutlich merkt ist, daß der erste Compilerlauf nach dem PC-Start länger dauert. D.h. das Laden des Compilers selbst in den RAM ist überwiegend. Peter
Peter Dannegger schrieb: > Mit der Optimierung:--combine -fwhole-program > werden auch alle nicht benutzten Funktionen gelöscht. damit hadere ich immer Ich finde es blöd, dass AvrStudio, Eclipse, oder auch Jörgs Makefile Tool nur Makefiles erstellen, in denen alle Files separat übersetzt werden. Und bei Makefiles blicke ich nicht so richtig durch. vielleicht hat ja jemand ein schönes Übersichtliches Template
Vlad Tepesch schrieb: > Und bei Makefiles blicke ich nicht so richtig durch. Ich auch nicht. Ich benutze immer eine Batch, die alle *.c im aktuellen Verzeichnis compiliert. Hier findest Du ein Beispiel: http://www.mikrocontroller.net/attachment/94173/124Bus.zip Peter
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.