Forum: Mikrocontroller und Digitale Elektronik AVR: ISR mit internal linkage: keine Linker-Fehlermeldung


von BMC (Gast)


Lesenswert?

Deklariere ich eine ISR fälschlicherweise mit internal linkage
1
static void isr() __asm__("__vector_5") __attribute__ ((__signal__, __used__)); 
2
void isr() {
3
    // ...
4
}
5
int main() {while(true){}}

so hätte ich eigentlich eine Warnung vom Linker erwartet, dass die 
Funktion dann nicht in den Interrupt-Vektor eingetragen wird. Kommt aber 
leider nicht.

Bitte keine Kommentare, dass das natürlich falsch ist: weiß ich doch. 
Ich möchte nur verstehen, warum da keine Fehlermeldung kommt bzw. wie 
ich eine Meldung bekommen könnte.

von MaWin (Gast)


Lesenswert?

Woher soll der Linker wissen, dass du versucht hast eine ISR zu 
implementieren?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es fehlt Attribut "__externally_visible__".

von BMC (Gast)


Lesenswert?

Johann L. schrieb:
> Es fehlt Attribut "__externally_visible__".

Das ist nicht die Frage

von Oliver S. (oliverso)


Lesenswert?

Aber die Antwort.

Oliver

von MaWin (Gast)


Lesenswert?

BMC schrieb:
> Das ist nicht die Frage

Ja. Du hast es halt falsch gemacht.

Warum sollte der Linker Heuristiken haben, die sowas erkennen?

Du hast halt eine lokale Funktion implementiert und keine ISR. Mache es 
richtig, dann funktioniert es auch.

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


Lesenswert?

BMC schrieb:
> warum da keine Fehlermeldung kommt

Aus Linkersicht ist alles in Ordnung, denn er hat default-Vektoren für 
alles.

Wenn, hätte der Compiler eine Chance, das anzumerken. Er sieht, dass du 
__vector_* definierst und er sieht auch, dass das nicht global ist. Hat 
eben nur keiner einen Test dafür im Compiler implementiert bislang.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Das Problem ist, dass der Code ohne externally_visible falsch ist. Und 
mit externally_visible, kommt der Code erst garnicht zum Linker (da 
static).

Bevor du Warnungen vom Linker erwartest (die es nicht gibt) mach erst 
mal korrekten C/C++ Code.

Sowas gehört eh in einen System-Header, und wenn man die falsch hat, hat 
man nunmal schlechte Karten.  Daher nimmt man ISR aus avr/interrupt.h 
der AVR-LibC als include oder als Vorlage für einen eigenen 
System-Header.

Ohne externally_visible dürfen Optimizer die Funktion in eine lokale 
umwandeln, und die wird nie in einer IRQ-Tabelle auftauchen.  Daher ist 
der Code ohne externally_visible nicht korrekt.

: Bearbeitet durch User
von g457 (Gast)


Lesenswert?

> Mache es richtig, dann funktioniert es auch.

Gibt es in den üblichen AVR-Toolchains nicht ein extra Marko wie ISR() 
genau dafür? Dessen Nutzung ersparte manuelle Fehler.

von BMC (Gast)


Lesenswert?

Jörg W. schrieb:
> Wenn, hätte der Compiler eine Chance, das anzumerken. Er sieht, dass du
> __vector_* definierst und er sieht auch, dass das nicht global ist. Hat
> eben nur keiner einen Test dafür im Compiler implementiert bislang.

Ja, sowas hatte ich erwartet ;-)

Johann L. schrieb:
> Ohne externally_visible dürfen optimizer die Funktion in eine lokale
> umwandeln, und die wird nie in einer IRQ-Tabelle auftauchen.

Ok, das wusste ich nicht. D.h. ein Optimizer darf external-linkage zu 
internal-linkage ändern. Kann doch aber nur bei LTO gemacht werden, 
oder?

von BMC (Gast)


Lesenswert?

Und Leute, spart Euch die Hinweise, dass das falsch ist:

BMC schrieb:
> Bitte keine Kommentare, dass das natürlich falsch ist: weiß ich doch.

von MaWin (Gast)


Lesenswert?

BMC schrieb:
> D.h. ein Optimizer darf external-linkage zu
> internal-linkage ändern.

Du hast es doch gar nicht als external-linkage angegeben.

von MaWin (Gast)


Lesenswert?

BMC schrieb:
> Und Leute, spart Euch die Hinweise, dass das falsch ist:
>
> BMC schrieb:
>> Bitte keine Kommentare, dass das natürlich falsch ist: weiß ich doch.

Naja, deine Frage ist eben: Ich mache X, will aber Y. Warum warnt der 
Compiler/Linker mich nicht?
Und ja, diese Frage kann man stellen und sie ist auch oft angebracht.
Aber in diesem Fall eher nicht. Das hier ist ein Superspezialfall, wenn 
du deine eigenen Systemheader selbst neu implementierst.

Nutze einfach die ISR-Makros aus deinen Systemheadern und gut ist.

Deshalb ist hier die Antwort: Du machst es halt falsch.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

BMC schrieb:
> D.h. ein Optimizer darf external-linkage zu internal-linkage ändern.
> Kann doch aber nur bei LTO gemacht werden, oder?

Das umfasst alle globalen Optimierungen, nicht nur LTO.

> Bitte keine Kommentare, dass das natürlich falsch ist: weiß ich doch.
> Ich möchte nur verstehen, warum da keine Fehlermeldung kommt bzw. wie
> ich eine Meldung bekommen könnte.

Erweiter ./gcc/config/avr/avr.cc::avr_set_current_function() oder 
ähnliche Stellen, die dafür geeignet sind.

https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/config/avr/avr.cc;h=c193430cf073b00238c250f9a690b1a97c62f87a;hb=HEAD#l1021

: Bearbeitet durch User
von BMC (Gast)


Lesenswert?

Johann L. schrieb:
> BMC schrieb:
>> D.h. ein Optimizer darf external-linkage zu internal-linkage ändern.
>> Kann doch aber nur bei LTO gemacht werden, oder?
>
> Das umfasst alle globalen Optimierungen, nicht nur LTO.

Wie kann der Optimierer beim Übersetzen einer TU entscheiden, das 
external-linkage zu internal-linkage geändert werden darf, wenn nicht 
LTO verwendet wird?

von MaWin (Gast)


Lesenswert?

BMC schrieb:
> Wie kann der Optimierer beim Übersetzen einer TU entscheiden, das
> external-linkage zu internal-linkage geändert werden darf, wenn nicht
> LTO verwendet wird?

Gar nicht.

Und das ist, wie gesagt, ja auch gar nicht, was hier passiert.
Die Funktion hatte nie external-linkage.

von BMC (Gast)


Lesenswert?

MaWin schrieb:
> Und das ist, wie gesagt, ja auch gar nicht, was hier passiert.
> Die Funktion hatte nie external-linkage.

Wir sind hier in der Diskussion ja schon einen Schritt weiter: natürlich 
schließen sich `static` und externally_visible gegenseitig aus bzw. es 
wirkt sich eben nur auf non-static aus.

Johann L. schrieb:
> Ohne externally_visible dürfen Optimizer die Funktion in eine lokale
> umwandeln, und die wird nie in einer IRQ-Tabelle auftauchen.  Daher ist
> der Code ohne externally_visible nicht korrekt.

Daher verstehe ich Johann so, dass non-static Funktionen (external 
linkage) zu internal linkage umgewandelt werden können, sofern kein 
_externally_visible_ angegeben ist. Und das erscheint mir 
unverständlich.

von MaWin (Gast)


Lesenswert?

BMC schrieb:
> Daher verstehe ich Johann so, dass non-static Funktionen (external
> linkage) zu internal linkage umgewandelt werden können, sofern kein
> externally_visible angegeben ist. Und das erscheint mir
> unverständlich.

Das kann es nur mit LTO (und je nachdem noch whole program 
optimization).

von BMC (Gast)


Lesenswert?

Johann L. schrieb:
> BMC schrieb:
>> D.h. ein Optimizer darf external-linkage zu internal-linkage ändern.
>> Kann doch aber nur bei LTO gemacht werden, oder?
>
> Das umfasst alle globalen Optimierungen, nicht nur LTO.

Genau das war doch auch meine Vermutung.

Johann scheint da anderer Meinung zu sein.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wie gesagt, alle globalen Optimierungen: -flto, -fwhole-program. oder 
wie die heißen mögen, z.b. bei clang/llvm.

Prinzipiell ist es keine gute Idee, die Korrektheit eines Programms von 
Optimierungen abhängig zu machen.  Für vanilla C/C++ kann das nur 
bedeuten, dass das Programm UB ist oder ill-formed.

Bei Features jenseits des Standards wie __asm oder Attributen muss man 
sich eben an das halten, was die Toolchain vorgibt, auch wenn sie nicht 
für jeden unsinnigen Code explizit austextet, dass er unsinnig ist.

Ich versteh auch nicht, worüber noch groß diskutiert wird und Unklarheit 
besteht.  Du kannst

0) Auf falschem Code bestehen (scheint ja dein Favorit zu sein) und 
Design-Pattern Garbage-in/Garbage-out verwenden.

1) Korrekten Code schreiben, also mit externally_visible.

2) AVR-LibC avr/interrupt.h verwenden anstatt nochmal bei der Ursuppe 
anzufangen.

3) Den Compiler erweitern und deine eigene Version pflegen.

Code wie im OP wird man doch ohnehin in einen Convenience Header / Makro 
verstecken wollen, so dass die Chance einer falschen Verwendung 
minimiert wird.

von BMC (Gast)


Lesenswert?

Johann L. schrieb:
> Wie gesagt, alle globalen Optimierungen: -flto, -fwhole-program.
> oder
> wie die heißen mögen, z.b. bei clang/llvm.

Ok, gut. Dann ist es also so, wie ich es vermutet habe: das LTO stand 
für mich pars-pro-toto.

> Ich versteh auch nicht, worüber noch groß diskutiert wird und Unklarheit
> besteht.

Es bestand keine Unklarheit - jedenfalls nicht bei mir, das habe ich 
oben auch schon geschrieben.

Lediglich habe ich mich gewundert, dass bei meinem mutwillig falschen 
Code, keine Warnung entstand. Das war alles.

> 0) Auf falschem Code bestehen (scheint ja dein Favorit zu sein) und
> Design-Pattern Garbage-in/Garbage-out verwenden.

Nö. Es war reine Neugier zu erfahren, warum die Dinge so sind, wie sie 
eben sind.

> 1) Korrekten Code schreiben, also mit externally_visible.

Nö.

> 2) AVR-LibC avr/interrupt.h verwenden anstatt nochmal bei der Ursuppe
> anzufangen.

Klaro.

> 3) Den Compiler erweitern und deine eigene Version pflegen.

Vielleicht.

> Code wie im OP wird man doch ohnehin in einen Convenience Header / Makro
> verstecken wollen, so dass die Chance einer falschen Verwendung
> minimiert wird.

Na klar, habe auch nichts anderes behauptet. Es war ja reine Neugier, 
was dort passiert und warum da keine Warnung kam. Nun ist es geklärt - 
es ist einfach nicht realisiert.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Gut, kann man natürlich einbauen, eine Diagnostic dass 
"externally_visible" erforderlich ist wenn Attribut "interrupt" und/oder 
"signal" vorhanden sind.

Auf die Linkage zu testen würde nicht funktionieren.

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.