AVR: ISR mit internal linkage: keine Linker-Fehlermeldung

Gast #7307292
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.

Persönliche Seite #7307326
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.

Gast #7307334
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?

Gast #7307363
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.

Persönliche Seite #7307377
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

Gast #7307397
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?

Gast #7307413
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.

Gast #7307434
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.

Gast #7307461
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).

Gast #7307464
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.

Persönliche Seite #7307518
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

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

  2. Korrekten Code schreiben, also mit externally_visible.

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

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

Gast #7307529
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.

  1. 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ö.

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

Klaro.

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren