mikrocontroller.net

Forum: Compiler & IDEs Wie ungenutzten Code nicht linken lassen?


Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachdem ich zu einem MSP430-Projekt Code für MMC/SDC kopiert habe, der
(noch) nirgends verwendet wird und auch keine ISR enthält, ist das
Programm deutlich größer; das BSS-Segment ist sogar dreimal größer und
wie ich mittels StackCheck (example aus dem CVS) sehe, ist der Stack
deshalb nun kurz vor'm overflow!
Ich habe schon Optionen wie -Os, --gc-sections und -ffunction-sections
ausprobiert, aber ohne Erfolg.
Wie bekommt man denn unbenutzten Code eleminiert?

Bisher war ich ja der Meinung, daß der Linker ungenutzten Code nicht
linkt, so daß ungenutzter Code automatisch nicht im fertigen Programm
ist, aber das stimmt leider nicht.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übliche Linker linken auf Objektdateieebene; wenn Dein ungenutzer Code
zusammen mit genutztem Code in einer Objektdatei steht, wird er auch
zum Endprodukt gelinkt.
Auch deswegen ist es sinnvoll, Code auf mehrere Objektdateien
aufzusplitten.

Diese entsprechen einzelnen C-Sourcefiles, die einzeln zu übersetzen
sind (per Makefile) und nicht, wie hier leider des öfteren gesehen, per
#include-Anweisung eingebunden werden sollten. In letzerem Falle ergibt
das ganze nur eine einzelne Objektdatei ...

Modernere Linker können (mit Unterstützung durch den Compiler) auch auf
Funktionsebene linken, in diesem Falle enspricht eine Objektdatei im
Grunde genommen einer Library. Ob aber ein Compiler für so "kleine"
Prozessoren wie AVR, MSP430 o.ä derartiges unterstützt, entzieht sich
gänzlich meiner Kenntnis.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Rufus T. Firefly:
Der Code ist doch aufgesplittet; deshalb ist es mir ja aufgefallen.
Ich könnte die betreffenden Dateien über defines leeren, aber das
sollte der Linker doch besser können.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du verwendest mehrere Sourcefiles und linkst auch die erzeugten
Objektdateien, verwendest also nicht #include "blafusel.c"?

Dann muss ich gestehen mit meinem Latein am Ende zu sein.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pack alles in eine library, nur aus dieser werden die Objektmodule
nur bei Bedarf extrahiert.  Alles, was auf der Kommandozeile steht,
wird immer gelinkt (du wirst dir ja was dabei gedacht haben, es auf
die Kommandozeile zu schreiben).

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rufus T. Firefly:
*.c-Dateien braucht man nicht zu includieren, denn man kann dem
Compiler ja mehrere *.c-Dateien übergeben, selbst wenn man kein
Makefile verwendet.

@Jörg Wunsch:
Eine Library ist doch nur ein Objektfile, oder gibt's da noch
Unterschiede?

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rolf!

>Eine Library ist doch nur ein Objektfile, oder gibt's da noch
>Unterschiede?

Oh ja! Eine Library ist "nur" ein Archiv aus mehreren Objektdateien.
Wenn Du für jede Funktion eine eigene Quelldatei anlegst und aus dieser
eine Objektdatei erstellst, kannst Du sie nachher mit dem
Archivierungstool [avr-]ar zu einer Library zusammenfügen. Der Linker
kann dann, anhand der nicht aufgelösten Referenzen, entscheiden, was er
aus diesem Archiv benötigt und was nicht.

Ich habe dazu auch mal einen kleinen (möglicherweise nicht ganz
vollständigen) Artikel im Wiki geschrieben, siehe
  -> http://www.mikrocontroller.net/articles/Libraries

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:

Den Namen des Archivierungstools kannst Du natürlich beliebig
ersetzen:

 - auf dem PC:     ar
 - auf den avr:    avr-ar
 - auf den msp430: msp430-ar
 - auf den arm:    arm-elf-ar
 - ...

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg: Du hast natürlich recht. 's war ein langer Tag, gestern. (Linken
mit Libraries<->Objektdateien). Irgendwie war ich auf den -möglichen-
#include-Anfängerfehler fixiert.

@Rolf: Ich wollte nicht so deutlich schreiben, daß #include
"blafusel.c" in meinen Augen ein Fehler ist, da sich hier des öfteren
schon Leute wegen banaleren Dingen auf die Füße getreten fühlten.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rufus T. Firefly:
Das Includieren von *.c-Dateien ist zwar schlechter Stil, aber es gibt
noch einiges schlimmere, beispiespielsweise Asssembler-Makros in *.c
oder *.h-Dateien; wenn man zum Prettyprinting den indent drüber laufen
läßt, wird der C-Code zwar schön formattiert, der Assembler-Code meist
unbrauchbar.
Anstatt den Assembler-Code in *.s-Dateien zu packen (und notfalls zu
inkludieren) landet er leider insbesondere bei Kernel-Sourcen häufig
ganz woanders.
Wenn man mal den indent, oder einen anderen Prettyprinter/Beautyfier
über *.[ch] in den Linux-Kernel-Sourcen laufen lässt, gibt das wenig
erfreuliche Ergebnisse und deckt z. B. viele Treiber auf, die sich
nicht einmal kompilieren lassen, weil fundamentales wie das
Klammer-Gleichgewicht nicht erfüllt ist, da die Dateien nur angefangen
wurden.

@Patrick Dohmen:
Ok, ich seh' mir das mal an und werde wohl ALLE *.c-Dateien in
Libraries umwandeln.

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich das jetzt richtig verstehe, willst Du für jede Quelldatei eine
Library erstellen? So war das nicht gedacht...

foo.c {func1, func2} -> foo.o
bar.c {func3} -> bar.o

foo.o, bar.o -> libfoobar.a

foo.o enthält zwei Funktionen, die immer beide im Endprodukt vorhanden
sind, sobald eine der Funktionen im Code referenziert wird.

bar.o enthält eine Funktion die, unabhängig vom Referenzieren einer
Funktion aus foo.c, nur dann im Endprodukt vorhanden ist, wenn sie auch
referenziert wird.

Autor: ●● pit ●. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
benutzte symbole kannst du mit

gcc ... -Wl,--retain-symbols-file <file>

festlegen, wobei in <file> eine liste mit den zu linkenden symbols
stehen muss, alle anderen werden ignoriert.

(nb: hab das auf avr aber noch nie probiert)

der Linker kann ansonsten nur auf .o file ebenen alles oder nichts
linken. (--[no]-whole-archive) das ist aber nur für .a oder .so's
interessant.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe nun mal bis auf die Datei mit main() alle in Libs gepackt
und das Ergebnis ist:

Vorher:
 > msp430-size aout.elf
   text    data     bss     dec     hex filename
  19476      36    1596   21108    5274 aout.elf

Nachher:
> msp430-size aout.elf
   text    data     bss     dec     hex filename
  17192      28     564   17784    4578 aout.elf

Das sieht schon deutlich besser aus.
Zum realistischeren Vergleich habe ich mal nachgesehen, was ohne den
ungenutzten MMC-Code eingespart wird:

before:
   text    data     bss     dec     hex filename
  17572      30     568   18170    46fa aout.elf

after:
> msp430-size aout.elf
   text    data     bss     dec     hex filename
  17192      28     564   17784    4578 aout.elf

Neben einer bekannt bisher ungenutzten Variablen wurden auch einige
aktuell brachliegende Funktionen und eine weitere Variable
rausgeworfen.

Nun fehlt mir noch ein Makefile, daß dies automatisch macht.
Kann mal jemand ein Beispiel posten?

Übrigens haben Optionen wie --retain-symbols-file -gfull --gc-sections
-fdata-sections -ffunction-sections -fssa-dce -dead_strip nichts
gebracht.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, in "make GE-PACKT", ISBN 3-8266-1442-9, habe ich gefunden wie man
es macht.
Ich schalte dann bei allen meinen Projekten vor dem Linker den
Archivierer und in die einzige, nicht zu einer Lib konvertierte Datei,
kommt nur die Main-Funktion.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach dem Listing-File funktioniert es immer noch nicht richtig: Selbst
wenn ich, bis auf main (das nur einen Funktionsauruf macht), alles an
Funktionen und Varablen in Bibliotheken packe, gibt es immer noch
dutzende Funktionen und andere Objekte (z. B. konstante Felder), die
nie genutzt und auch im Sourcecode nirgendwo aufgerufen/verwendet
werden und die trotzdem gelinkt werden!
Diese Funktionen und konstanten Felder kann ich auskommentieren, ohne
daß es nachher beim Compilieren +Linken auch nur eine Warnung gibt!
Im Listing-File sehe ich sogar die MMC-Funktionen, die ungenutzt sind
und ohne Probleme auskommentiert werden können!

Wie bekomme ich den Linker dazu toten Code nicht zu linken?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, aber das klingt jetzt nach Kristallkugel...

Kannst du das in einem Miniprojekt mit 3 Dateien nachvollziehbar
gestalten?

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

wurde hier nicht schon erwähnt das der Linker immer auf Objekt-Ebene
arbeitet. Wenn du jetzt also alle MMC-Funktionen in einen C-Datei
packst, diese dann in ein Object (*.o) compilierst und abschließend in
ein Archiv (*.a) packst wird immer noch das ganze Object gelinkt wenn
du auch nur eine Funktion aus dem Object verwendest. Du mußt jede
Funktion in ein eigenes Object packen um wirklich auf Funktionsebene
linken zu können.

Matthias

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich dachte eigentlich, das hätte Rolf bereits verstanden.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias Weißer:
Aus der mmc.c wird doch absolut nix verwendet; wenn ich die im Makefile
weglasse, wird ohne die gelinkt. Wenn ich die aber als Bibliothek
einbinde, landen Funktionen daraus im elf-file. Ich finde da sogar aus
einer anderen Bibliothek eine Funktion zur Berechnung des
Binominalkoeffizienten, die ich nirgends verwende und einigen anderen
toten Code.
So wie beschrieben wird nicht gelinkt!

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Merkwürdig; nun sind die mmc-Sachen wieder draußen, nachdem ich nochmal
gecheckt habe.
Aber es bleibt noch das Problem, daß die Libs jeweils komplett gelinkt
werden, obwohl der Linker nur einzelne Referenzen auflösen sollte, also
nur referenzierten Code linken sollte.
Tatsächlich werden die Libs aber komplett gelinkt. Wie kann man das
abstellen?

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

@Jörg
Offensichtlich nicht.

@Rolf
Hast du dir mein Posting überhaupt durchgelesen und verstanden? Der
Linker der gcc arbeitet eben auf Object-Ebene und nicht auf der Ebene
einzelner Referenzen. Wie du dein gewünschtes Verhalten realiseren
kannst hab ich in
http://www.mikrocontroller.net/forum/read-2-215461... bereits
beschrieben (weiteres teilen deiner Module in mehrere *.o Dateien)

Matthias

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rolf:

Hast Du Dir meinen Artikel durchgelesen?
Die Option 's' für 'ar' ist sehr wichtig, sie sorgt für das
Erstellen eines Index der Library.

Wenn ich mich richtig erinnere:
Erstellt man keinen Index für die Library, dann kann der Linker nur das
komplette Archiv linken!

Autor: tenner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sach mal, warum linkst du das obj-file überhaupt, wenn sowieso keine
funktionen daraus genutzt werden???

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Matthias Weißer:
Ein Objekt ist in C99 "A region of data storage in the execution
environment, the contents of which can represent values.", also
beispielsweise eine int-Variable oder eine Funktion.
Und das Problem ist, daß der Linker diese nicht gezielt linkt, sondern
stattdessen einfach die ganze Lib anhängt und nur nötige Referenzen
reinpackt.

@Patrick Dohmen (OldBug):
Ich verwende -rcs; da ist s bei.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, wir reden hier von Objektmodulen, also gewissermaßen dem
Kompilat einer `translation unit', um im C99-Jargon zu bleiben.
Das ist die Kategorie, in der der Linker denkt.  Der hat nämlich
von C keine Ahnung, der kann allen möglichen Krempel linken.

Du solltest bitte deine C-Programme funktionsweise (bzw. eben
objektweise, wenn du das gern so hättest) zerhacken, einzeln
compilieren und in eine Bibliothek stopfen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falls dich der Begriff ,Objekt' hier verwirrt: ist seit 20 Jahren
gängig dafür.  Sollte eigentlich wohl ,Objektcode' heißen, im
Gegensatz zu ,Quellcode'.  Daher die Endung .o (oder .obj in anderen
Systemen).

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, dann muß ich aus gut 10 Quellcodedateien (+ebensoviele Header) ca.
50 machen ...

Gibt's denn keine Tools um toten Code zu beseitigen, beispielsweise
Linker, die nur das linken, was wirklich referenziert wird anstatt
jeden Müll mit zu linken?
Helfen würde auch schon ein Pre-Linker, der alle nicht referenzierten
(C99-)Objekte aus den Bibliotheken/Objektdateien entfernt.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
War nicht für GCC 4.0 eine Funktion angekündigt die ungenutzten Code
entfernt?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, ich finde das einen ziemlichen Hack, -ffunction-sections plus
-gc-sections sollte das wohl tun, aber selbst das will ja bei Rolf
nicht funktionieren.

Ich verstehe aber nach wie vor nicht, was an ,,eine Funktion pro
Datei'' für eine Bibliothek so schlimm ist.  Unix-Bibliotheken
können seit 30 Jahren ganz gut damit leben.  Der Vorteil ist, dass
man halt selbst die Kontrolle hat, was gemeinsam reingeht, statt
das irgendwelchen ominösen Heuristiken zu überlassen.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andererseits finde ich es auch irgendwie albern irgend einen
Hardwaretreiber der aus vielen kleinen 3-Zeilern besteht in einzelne
Dateien aufzusplitten.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Brauchst du bei dem den wirklich jede Funktion unabhängig
voneinander?

Ansonsten bleibt natürlich immer noch die Variante, wie sie z. B.
die libgcc selbst macht: eine große Datei, die mit #ifdef n-mal
in n verschiedene Objektmodule übersetzt wird.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Braucht man natürlich nicht immer. Aber der libgcc-Hack zeigt doch auch
dass das Ganze im Grunde eine unnötige Belastung ist die der Compiler
einem ohne weiteres abnehmen könnte.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, wenn ich es partiell einschalten könnte, wäre ich ganz
zufrieden damit.  Aber nur global für die ganze Applikation?
Da misstraue ich der Heuristik zu sehr.  Vielleicht bin ich ja
auch konservativ. :)

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm. Das mit der Heuristik verstehe ich nicht; sollte es für den
Compiler/Linker nicht ganz trivial sein alle referenzierten Funktionen
zu finden?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun ja, was willst du alles drin haben?

Gängiges Beispiel sind all die Initialisierungsdinge.  crt1.o
muss man also schon mal auf jeden Fall ausnehmen, aber eben auch
Teile, die man selbst schreibt und die in die Initialisierung
eingehen wie die Aktivierung von externem RAM.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist doch ganz klar was reingehört: Der Starup-Code, der vor main
gelinkt wird und ansonsten muß rekursiv nur das rein, was von Main (u.
den ISRs) verwendet wird.
Da ist ganz klar, ob ein Objekt referenziert wird oder nicht.
Schließlich muß das, was verwendet wird (nicht-toter Code) ja irgendwie
erreicht werden, also von irgendwo referenziert werden. Und wenn es
keine Kette von Referenzen von main oder einer ISR gibt, ist der Code
tot; der wird niemals ausgeführt (falls nicht zufälligerweise ein wild
gewordener Pointer auf ihn und zudem an die richtige Stelle kommt).

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, mein eigenes XRAM-Init wird effektiv Bestandteil des
Startup-Codes [__attribute__((section(".init3")))] und ist nirgends
referenziert.  Die garbage collection würde es rauswerfen.  Ich müsste
für solche Dinge also explizit auf der Linker-Kommandozeile mit -u
erzwingen, dass sie aufgenommen werden.  Für den vorgefertigten
Startup-Code müsste man ähnliche Hac^H^H^HWorkarounds festlegen um zu
erreichen, dass der Linker sie nicht rauskippt (da dem bei der
GC-Methode ja völlig wurscht ist, ob der ,,tote'' Code aus einer
Bibliothek oder einer direkt angegebenen Objektdatei stammte).

Ich finde das alles mindestens genaus eklig anzufassen wie die
Eine-Objektdatei-pro-Bibliotheksfunktion-Methode.

Autor: Rolf F. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg Wunsch:
Der Linker bekommt doch den Einstiegspunkt und über den wird auch dein
Startup-Code referenziert.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein.  Der wird über den Linkerscript und die .initN sections
verkettet.  Die Symbole darin sind Schall und Rauch, die haben
nur erläuternden Charakter und werden von niemandem referenziert.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.