Forum: Compiler & IDEs LTO und weak references und Bibliotheken


von Marc P. (marcvonwindscooting)


Lesenswert?

Hallo Leute,

nachdem ich im 'Teufelswerk'-Thread einiges ueber den LTO vom GCC 
erfahren habe, spiele ich mit dem Gedanken, meine Bibliothek zu aendern. 
Bisher hacke ich grosse *.c-Files mit einem Perl-Script in kleine 
Stuecke (die Stuecke markiere ich mit speziellen Kommentaren im c-File) 
und pack die *.o-Stueckchen in eine lib*.a . Das kann ich mir dank LTO 
ja dann sparen. Soweit ist noch alles gut.

ABER:

Mit dem Bewusstsein, dass ein *.o die Einheit ist ueber die beim Linken 
entschieden wird ob sie ins fertige Programm kommt oder nicht habe ich 
auch folgenden Kniff benutzt: Manche Bibliotheks-*.c-Files enthalten 
eine normale Funktion (moduleXyInit(...)), die im *.h ebenfalls 
auftaucht und im Hauptprogramm gerufen wird und zus"atzlich noch einen 
Interrupt-Handler B. Dieser Interrupt-Handler B wird sozusagen vom 
Linker unbeabsichtigt (aber von mir beabsichtigt!) ins fertige Programm 
gelinkt und ersetzt dann eine weak-Reference auf einen 
dummy-Interrupt-Handler A.
Ist das noch sauberes Programmieren oder schon fragwuerdige Praktik?

Macht der LTO solche Sachen dann auch noch richtig? Der 
Interrupt-Handler B ist ja streng genommen nicht notwendig und koennte 
einfach wegoptimiert werden, weil Handler A schon vorhanden?


Oder wie macht ihr das mit dem automatischen Installieren von 
ISR-Handlern aus Bibliotheksmodulen in der ISR-Vector-Tabelle (im 
FLASH)?

von Haro (Gast)


Lesenswert?

Marc P. schrieb:
> Hallo Leute,nachdem ich im 'Teufelswerk'-Thread einiges ueber den LTO
> vom GCC erfahren habe, spiele ich mit dem Gedanken, meine Bibliothek zu
> aendern. Bisher hacke ich grosse *.c-Files mit einem Perl-Script in
> kleine Stuecke (die Stuecke markiere ich mit speziellen Kommentaren im
> c-File) und pack die *.o-Stueckchen in eine lib*.a . Das kann ich mir
> dank LTO ja dann sparen. Soweit ist noch alles gut.ABER:Mit dem
> Bewusstsein, dass ein *.o die Einheit ist ueber die beim Linken
> entschieden wird ob sie ins fertige Programm kommt oder nicht habe ich
> auch folgenden Kniff benutzt: Manche Bibliotheks-*.c-Files enthalten
> eine normale Funktion (moduleXyInit(...)), die im *.h ebenfalls
> auftaucht und im Hauptprogramm gerufen wird und zus"atzlich noch einen
> Interrupt-Handler B. Dieser Interrupt-Handler B wird sozusagen vom
> Linker unbeabsichtigt (aber von mir beabsichtigt!) ins fertige Programm
> gelinkt und ersetzt dann eine weak-Reference auf einen
> dummy-Interrupt-Handler A. Ist das noch sauberes Programmieren oder
> schon fragwuerdige Praktik?Macht der LTO solche Sachen dann auch noch
> richtig? Der Interrupt-Handler B ist ja streng genommen nicht notwendig
> und koennte einfach wegoptimiert werden, weil Handler A schon
> vorhanden?Oder wie macht ihr das mit dem automatischen Installieren von
> ISR-Handlern aus Bibliotheksmodulen in der ISR-Vector-Tabelle (im
> FLASH)?

Erstmal, für das was du vorhast brauchst du keine LTO.
Da ist eher -ffunction-sections und -fdata-sections das Mittel der Wahl. 
Dadurch sparst du dir dein Skripgesteuertes Zerhacken und deine Lib.a 
hat auch nur ein Objekt-file.

Aber zu deiner Frage: ja, bei LTO kann es dir passieren dass dir eine 
ISR flöten geht, da diese ja nicht direkt benutzt wird sondern von der 
Hardware angesprungen wird.
Im Zweifel das Listing kontrollieren!
Der gcc kennt allerdings ein Attribut um Funktionen zu markieren die 
immer dazugelinkt werden sollen. always_use oder so ähnlich. Google oder 
das gcc Manual helfen dir weiter.
Es schadet nicht, damit deine ISRs zu markieren.

von Marc P. (marcvonwindscooting)


Lesenswert?

mit -ffunction-sections kann das was nach dem ABER oben steht nicht mehr 
funktionieren, das die ISR B dann gar nicht mehr als Kandidat in Frage 
kommt.
Nicht so gut...
Daher die Hoffnung mit dem LTO.

Haro schrieb:
> Aber zu deiner Frage: ja, bei LTO kann es dir passieren dass dir eine
> ISR flöten geht, da diese ja nicht direkt benutzt wird sondern von der
> Hardware angesprungen wird.

Aber von meinen Assembler-Sachen (Startup Code) laesst der LTO doch 
hoffentlich die Finger, oder?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Haro schrieb:
> Aber zu deiner Frage: ja, bei LTO kann es dir passieren dass dir eine
> ISR flöten geht, da diese ja nicht direkt benutzt wird sondern von der
> Hardware angesprungen wird.

Käse. Wenn das ISR Makro aus der AVR-Libc verwendet wird, dann sind alle 
ISR-Routinen mit __attribute__((_used_)) markiert, d.h. der 
Compilerwird sie nicht wegwerfen weil sie unbenutzt sind / erscheinen.

Und der Linker kann sie nicht wegwerfen, weil sie vom Startup-Code (bzw. 
Vector-Tabelle) referenziert widd.

von Dr. Sommer (Gast)


Lesenswert?

Johann L. schrieb:
> Und der Linker kann sie nicht wegwerfen, weil sie vom Startup-Code (bzw.
> Vector-Tabelle) referenziert widd.
Und was hindert ihn daran, die auch noch mit wegzuwerfen? Dass sie 
auch mit __attribute__((used)) markiert sind... ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Johann L. schrieb:
>> Und der Linker kann sie nicht wegwerfen, weil sie vom Startup-Code (bzw.
>> Vector-Tabelle) referenziert wird.
> Und was hindert ihn daran, die auch noch mit wegzuwerfen? Dass sie
> auch mit __attribute__((used)) markiert sind... ;-)

Nö :-) Die Vector-Tabelle ist im Linker-Description als KEEP markiert:
1
 .text   :
2
  {
3
    *(.vectors)
4
    KEEP(*(.vectors))

attribute ist ein Konzept des Compilers, bereits im Assemblercode (.s) 
ist nichts mehr davon zu sehen -- außer eben den Effekt, daß die 
entsprechende Funktion nicht wegoptimiert ist.  D.h. im object-Code 
gibt's nix, was einem "used" entspricht.

Neben KEEP gibt's noch andere Mechanismen wie den Entry Point.

von Marc P. (marcvonwindscooting)


Lesenswert?

Danke fuer die Infos!
Jetzt wird einiges klarer - endlich weiss ich wozu das KEEP da ist :)

Ich denke ich versuche folgenden Weg:
Linker-Script schuetzt wie von Johann gezeigt mit KEEP die 
VectorTabelle. Der ISR default handler A muss dann ausserhalb der 
vectorTabellen-Section sein, dadurch also prinzipiell 'faellig' wenn 
seine weak reference durch eine starke Referenze B ersetzt sind => LTO 
kassiert default handler A dann, aber auch nur dann.

In der Lib fasse ich eine (beliebigen Namens) init-Funktion in einer 
Section (.text) (= ein C-File) mit der zum Modul gehoerenden ISR B 
zusammen und markiere sie mit __attribute__((used)). => B ueberschreibt 
A => LTO eliminiert A.

Fein!
Das mit den *.c - Schnipseln geht mir naemlich langsam auf den Zeiger: 
es sind mittlerweile knapp unter 500 und da braucht gcc dann schon ein 
wenig Zeit.

PS: ist uebrigens fuer ARM7/M0/M3 gedacht, aber das macht ja keinen 
prinzipiellen Unterschied.

von Marc P. (marcvonwindscooting)


Lesenswert?

Hab gestern abend den ersten Versuch gestartet das umzusetzen. Ein 
LED-blink-Programm hat dann auch funktioniert und war klein :) Target: 
LPC812 (Cortex-M0+, keine Divisionsbefehle!). Die ISR ist korrekt 
'gelinkt' worden.

Aber sobald ich eine Ausgaberoutine verwende, die Division (durch 10) 
verwendet: Krawummm!

Muss ich bei libgcc bzw. deren Ersatz etwas besonderes beachten bei 
Verwendung von LTO?

von Marc P. (marcvonwindscooting)


Lesenswert?

Marc P. schrieb:
> Muss ich bei libgcc bzw. deren Ersatz etwas besonderes beachten bei
> Verwendung von LTO?

Sorry meine Schuld ! Habe im Linker-Script text.unlikely-Sections 
verschlampert. Jetzt tut's!

Bilanz (gcc-4.8.1): ca. 1500 bytes statt (bisher) ca. 1800 bytes fuer 
Temperaturmessung mit DS75, Festkomma-Zahlen- und Textausgaben, und 
power-down.

Das lohnt sich halt besonders bei den ganz kleinen Microcontrollern, 
z.B. LPC810 mit nur 4k FLASH :-)

: Bearbeitet durch User
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.