Forum: Compiler & IDEs Linkeroptimierung


von Stephan V. (orca)


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

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.

von Markus J. (markusj)


Lesenswert?

-ffunction-sections -fdata-sections an den Compiler und --gc-sections an 
den Linker übergeben, damit sollten ungenutze Funktionen nicht mehr 
gelinkt werden.

mfG
Markus

von Andreas B. (Gast)


Lesenswert?

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.

von Stephan V. (orca)


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Oliver (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Andreas B. (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Stephan V. (orca)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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).

von (prx) A. K. (prx)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Vlad T. (vlad_tepesch)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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
Noch kein Account? Hier anmelden.