Forum: Mikrocontroller und Digitale Elektronik Wann Compiler-Optimierung in Embedded ausschalten


von Fpgakuechle K. (Gast)


Lesenswert?

Moin, moin

Zum Thema "Hardwarenahe Programmierung" bin ich über den Punkt 
gestolpert, das verschiedenen  Standards/Zertifizierungen ( im 
embedded-bereich) verlangen das die maschinelle Optimierung 
auszuschalten ist (cc -O0).

Beim  Nachzurecherchieren  diese "Hörensagen" stoße ich auf 
Widersprüche. Mal steht bei MISRA-C (Automobilbereich, 
Softwarezuverlässigkeit) wäre das so und auch bei höheren SIL Stufen 
(IEC 61508, Avionic etc), dann  erzählt mir ein erfahrenen 
MISRA-programmiere bei ihm hats immer auf -O3 gestanden trotz MISRA 
compliance.

Welche Erfahrung habt ihr damit gemacht, wann musste die Optimierung 
wirklich deaktiviert werden, nach welchen Standard und für welche 
Zielhardware wurde dabei entwickelt?

MfG,

von Freddie (Gast)


Lesenswert?

Meine Erfahrung aus 61508-Projekten:

Ein Projekt hatte diversitäre Kanäle, mit ganz unterschiedlichen 
Mikrocontroller-Architekturen und unterschiedlichen Compilern: gar kein 
Problem.

Ein anderes Projekt hatte homogene Kanäle mit dem selben Compiler: eine 
Diskussion mit der Benannten Stelle fand statt, war aber schmerzlos. 
Etwas verschärfte Auflagen, was Testen angeht, kamen dabei heraus, 
Optimierung wurde akzeptiert.

Man muß sich auch klar machen, daß "-O0" üblicherweise auch 
Optimierungen durchführt, nur halt die ganz einfachen. Irgendwann wird 
es sowieso philosophisch, wenn man das ganz konsequent durchziehen 
würde, dürfte kein Middle-End oder Back-End irgendwelche Änderungen am 
Parse-Tree vornehmen.

von Stefan F. (Gast)


Lesenswert?

Warscheinlich steckt die Idee dahinter, dass die komplexe Optimierungen 
eher fehlerhaft sind, als einfache.

In der Praxis stößt man jedoch außerst selten (wenn überhaupt jemals) 
auf Fehler im Compiler. Viel häufiger kommt es vor, das ein 
Programmierer sich nicht an die C Spezifikation gehalten hat und sein 
Programm nur mit Glück funktioniert. Da kann dann ein Wechsel zu einem 
anderen oder neueren Compiler plötzlich Probleme auslösen.

von Michael S. (rbs_phoenix)


Lesenswert?

Ist vielleicht ein bisschen Off-Topic aber ich habe mir die Frage schon 
ein paar mal gestellt:

Wie kann ein Compiler zu viel Optimieren? Die Funktion, die das Programm 
haben soll, beschreibe ich mit der Proframmiersprache, z.B. C. Wenn ich 
via SPI etwas empfange und darauf hin ein Sensor auslese, in den 
physikalischen Wert umrechne und zurück schicke, dann soll der Compiler 
das auch so umsetzen.

Wenn dabei etwas nicht stimmt und der Ablauf fehlerhaft umhesetzt wird, 
dann mache ich nicht die Optimierung sondern den Compiler dafür 
verantwortlich. Er hat schließlich nicht das gemacht, was ich ihm via 
Sourcecode gesagt habe. Und ich denke, ich würde mich dann auch auf die 
Suche nach einem neuen Compiler machermachen, dessen 
Optimierungafunktion auch optimiert und nicht verfählscht.

Kann mich da jemand erleuchten, vielleicht auch mit Beispiel?

von (prx) A. K. (prx)


Lesenswert?

Michael Skropski schrieb:
> Kann mich da jemand erleuchten, vielleicht auch mit Beispiel?

Der Forenklassiker: 
https://www.mikrocontroller.net/articles/Interrupt#Volatile_Variablen

Der Compiler macht auch mit Optimierung praktisch immer das, was man ihm 
sagt. Kleine Unterschiede bestehen jedoch oft zwischen dem, was man ihm 
sagen wollte und was man ihm aus seiner Sicht tatsächlich gesagt hat 
(*). Eingeschaltete Optimierung eines gut optimierenden Compilers 
verschärft diesen Effekt markant.

*: Wie in vielen Ehen geht es nicht zuletzt auch darum, was man alles 
nicht gesagt hat.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Stefan Us schrieb:
> Warscheinlich steckt die Idee dahinter, dass die komplexe Optimierungen
> eher fehlerhaft sind, als einfache.

Auf hohen Optimierungseinstellungen wird im Compiler selbst viel mehr 
Code durchlaufen, und dieser ist zusätzlich noch komplexer, und die 
Fehlersituationen werden subtiler. Dazu kommt dann noch, daß 
Optimierungen oft auch viel weniger tolerant gegen Fehler im zu 
übersetzenden Code sind.

> In der Praxis stößt man jedoch außerst selten (wenn überhaupt jemals)
> auf Fehler im Compiler.

Aber wenn, dann sind es meiner Erfahrung nach am ehesten welche im 
Optimizer.

> Viel häufiger kommt es vor, das ein Programmierer sich nicht an die C
> Spezifikation gehalten hat und sein Programm nur mit Glück funktioniert.

Wenn es allerdings um ein System geht, von dem Menschenleben abhängen 
wie der Code in einem ESP-Steuergerät oder gar einem Flugzeug-Autopilot, 
geht es in erster Linie darum, alles zu tun, was man kann, um 
Fehlfunktionen zu vermeiden und nicht nur das, was man kann, um die 
Schuld jemand anderem geben zu können. Im Zweifelsfall wird man das 
nicht mal können.

Michael Skropski schrieb:
> Und ich denke, ich würde mich dann auch auf die Suche nach einem neuen
> Compiler machermachen, dessen Optimierungafunktion auch optimiert und
> nicht verfählscht.

Und woran erkennst du das, bevor so ein Fehler passiert?

Ein anderer Aspekt noch: Sinnvolle Nutzung des Debuggers mit stark 
optimiertem Code ist je nach Compiler sehr schwer bis gar nicht möglich. 
Auch der generierte Assembler-Code ist nur noch schwer verständlich. 
Dementsprechend schwierig ist es, nachzuvollziehen, ob der generierte 
Assembler-Code korrekt ist.

: Bearbeitet durch User
von Michael S. (rbs_phoenix)


Lesenswert?

A. K. schrieb:
> Der Forenklassiker:
> https://www.mikrocontroller.net/articles/Interrupt#Volatile_Variablen

Ich nehme dafür eigentlich immer globale Variablen. Find ich angenehmer, 
als eine Variable durch vielleicht 3 Funktionen durchzuschleifen und 
eben sowas wie mit interrupts zu berücksichtigen. Nebenbei find ich es 
auch Übersichtlicher, wenn man mit gewissen Vorgaben die Namen definiert 
(z.B. komplett alles Groß sind defines, g_... sind globale Variablen und 
der Rest nicht). Speicherplatzbedarf einer globalen Variable ist ja auch 
so klein es geht. Sie wird bei Funktionsübergabe ja ggf mehr mals 
gespeichert oder zumindest die Adresse.

Die Schlüsselwörter wie static, volatile usw sollte man aber schon 
kennen. Doch da sehe ich die Schuld nicht beim Compiler, sondern der 
Programmierer hat da was vergessen.


Rolf Magnus schrieb:
> Und woran erkennst du das, bevor so ein Fehler passiert?

Wie soll man was erkennen, was noch garnicht aufgetreten ist? Wenn ich 
aber sehe, dass ein Compiler nicht das umsetzt, was ich ihm wirklich 
gesagt habe und für die Erkenntnis vielleicht eine Woche verbracht habe, 
würde ich mir einen anderen Compiler suchen, denn wer sagt, dass sowas 
nicht nochmal vorkommt. Zudem würde ich immer im Hinterkopf überlegen 
"Ist das jetzt wirklich ein Fehler meines Codes oder spackt der Compiler 
wieder".

Wenn ich jemanden überholen will und drücke aufs Gas, das Auto 
beschleunigt aber nicht, werde ich mich schnell nach ein anderem 
umsehen, am besten von einem ganz anderen Hersteller. Das Vertrauen wäre 
weg. Das gilt natürlich nicht, wenn ich versehentlich ein Tempolimit 
eingestellt habe. Mit dem Unterschied, dass da mein Leben von abhängig 
sein kann, beim Compiler allerdings eher nicht.

von Nase (Gast)


Lesenswert?

Ich bin jetzt auch mal pauschal: Optimierungen abschalten ist immer 
Unsinn.

Ich denke, man kann nun im Prinzip zwei Szenarien unterscheiden:

(1) Der Programmierer hält sich nicht an die Festlegung der Sprache. Der 
Optimierer verändert dann scheinbar die Semantik des Programms. Das 
umfasst etwa das leidliche volatile-Problem und vieles mehr.

(2) Compiler und/oder Optimierer haben einen Fehler. Klar, beide sind 
auch nicht fehlerfrei.

Gegen (1) hilft tatsächlich nur sauberes Programmieren. Man kann zwar 
die Optimierungen so lange frisieren, bis auch der (semantisch) 
fehlerhafte Programmcode (=fehlendes volatile) korrekt läuft (=Variablen 
nicht herausoptimieren). Und das ist auch leider gängige Praxis. Aber es 
ändert nichts daran, dass der Code fehlerhaft ist und etwas anderes 
beschreibt, als dem Programmierer vorschwebt. Früher oder später rumpelt 
das, pures Glücksspiel.

Mit (2) dagegen muss man zuweilen rechnen. Entgegen der weit 
verbreiteten Meinung (MISRA..) allerdings denke ich, dass man fehler in 
der Compiler/Optimierer-Toolchain unter Verwendung des Optimierers soger 
eher finden kann: Es wird mehr Code im Compiler durchlaufen, das ist 
richtig und steigert die Fehlerwahrscheinlichkeit. Es wird aber auch 
anderer Code durchlaufen. Latente Fehler, die anfangs nicht auffallen 
oder nicht nachvollziehbar sind, verändern sich recht wahrscheinlich, 
wenn der Optimierer mitarbeitet.

Grundsätzlich halte ich schließlich die Argumentation gegen den 
Optimierer von wegen "da wird mehr und komplexerer Code durchlaufen" für 
fragwürdig. Daran die Sicherheit eines Systemes zu bewerten ist grob 
fahrlässig. Woran bemisst man das denn? Dann dürfte man ja 
konsequenterweise auch irgendwann keine neuen Compilerversionen mehr 
verwenden, weil die durchlaufen auch immer mehr Code. Von 
Hardwaresynthese mal ganz zu schweigen...

von Freddie (Gast)


Lesenswert?

Nase schrieb:
> Dann dürfte man ja
> konsequenterweise auch irgendwann keine neuen Compilerversionen mehr
> verwenden, weil die durchlaufen auch immer mehr Code.

Betriebsbewährtheit ist tatsächlich ein Thema, und neue 
Compilerversionen in der Zulassungspraxis auch problematisch.

von drama (Gast)


Lesenswert?

Michael Skropski schrieb:
> Wie kann ein Compiler zu viel Optimieren? Die Funktion, die das Programm
> haben soll, beschreibe ich mit der Proframmiersprache, z.B. C. Wenn ich
> via SPI etwas empfange und darauf hin ein Sensor auslese, in den
> physikalischen Wert umrechne und zurück schicke, dann soll der Compiler
> das auch so umsetzen.

Häufig verlassen sich Leute auf bestimmtes Übersetzungsverhalten des 
Compilers, auch wenn das nirgendwo im C-Standard spezifiziert ist 
(undefined behavior!). Gerade bei höheren Optimierungsstufen knallt es 
dann gerne.

Wenn ein Programm nur mit -O0 funktioniert und selbst mit -O1 dann nicht 
mehr, weist es i.d.R. auf einen Fehler im Code hin, nicht auf einen 
Fehler des Compilers!

von Nase (Gast)


Lesenswert?

Freddie schrieb:
> Betriebsbewährtheit ist tatsächlich ein Thema, und neue
> Compilerversionen in der Zulassungspraxis auch problematisch.

Und selbst Bewährtheit ist hier eigentlich ein ganz schön schwaches 
Argument.

von Bernd K. (prof7bit)


Lesenswert?

Fpga Kuechle schrieb:
> bin ich über den Punkt
> gestolpert, das verschiedenen  Standards/Zertifizierungen ( im
> embedded-bereich) verlangen das die maschinelle Optimierung
> auszuschalten ist (cc -O0).

Das ist ein Widerspruch in sich: In diesen Umfeldern wird gerne auf 
"zertifizierte" Compiler bestanden. Das impliziert daß diese 
vollumfänglich getestet sind und für funktionierend befunden wurden. Die 
Forderung dann trotzdem auf gewisse Optionen dieser "zertifizierten" 
Compiler zu verzichten impliziert daß diese wohl anscheinend doch 
fehlerhaft sein könnten, mithin man sich also den ganzen 
Zertifizierungs-Schmu ebensogut getrost in die Haare hätte schmieren 
können.

Jedoch verdienen etablierte Hersteller ordentlich Geld mit dieser Kultur 
der gegenseitigen Beweihräucherung in geschlossener Gesellschaft, völlig 
losgelöst vom praktischen Nutzwert oder irgendeiner Logik, daher ist das 
nun mal einfach so und daran wird auch nicht gerüttelt.

Ich als Normalsterblicher nehme gcc und die üblichen Optimierungen, denn 
zum Glück schreibt mir hier keiner vor welche (womöglich suboptimalen) 
Werkzeuge und Einstellungen angeblich besser sein sollen nur weil sie in 
irgendeinem teuren Papier erwähnt werden, ich wähle sie stattdessen nach 
objektiven Kriterien der praktischen Tauglichkeit für den jeweiligen 
Verwendungszweck aus.

von Marian (phiarc) Benutzerseite


Lesenswert?

Michael Skropski schrieb:
> A. K. schrieb:
>> Der Forenklassiker:
>> https://www.mikrocontroller.net/articles/Interrupt#Volatile_Variablen
>
> Ich nehme dafür eigentlich immer globale Variablen. Find ich angenehmer,
> als eine Variable durch vielleicht 3 Funktionen durchzuschleifen und
> eben sowas wie mit interrupts zu berücksichtigen.
>
> Die Schlüsselwörter wie static, volatile usw sollte man aber schon
> kennen. Doch da sehe ich die Schuld nicht beim Compiler, sondern der
> Programmierer hat da was vergessen.

Kleiner Hinweis am Rande, wenn du globale Variablen zur Kommunikation 
mit Interrupts nutzt und die nicht volatile sind, ist es reines Glück, 
dass das funktioniert. volatile hat nämlich mit dem Scope einer 
Variablen rein gar nix zu tun.

von Fpgakuechle K. (Gast)


Lesenswert?

Stefan Us schrieb:
> Warscheinlich steckt die Idee dahinter, dass die komplexe Optimierungen
> eher fehlerhaft sind, als einfache.

Nein, IMHO geht es weniger um Fehler als darum das der Compiler die im 
Quelltext beschrieben Funktion in eine andere überführt als die 
verifiziert wurde.

Ergebnis der Zertifizierung soll die Sicherstellung sein das die 
Software das tut was sie soll und nie was anderes machen kann. (auch 
wenn das andere ergebnismäßig gleich wäre). Diese Überprüfung geschieht 
nun am C-Code, da Assembler oder Hexcode  zu kryptisch und zu lang sind 
als das man ihn 100% verifizieren kann. Man will ja auch die Funktion 
überprüfen und geht dann davon aus das die 1:1 Umsetzung des Compilers 
passt.

Und um den c-code einfach prüfbar zu halten, schränkt man den noch ein 
(MISRA-C), es darf nicht jedes C-konstrukt verwendet werden.

Beispielscenario: loop-unrolling.

Jetz hat man den Code zertififiziert, Programmzeilen gezählt und 
abgeschätzt das es so in den Speicher passt. Da kommt der Compiler daher 
und optimiert den code durch loop unrooling, er spart sich das dekrement 
des loop-index, den Vergleich  und die pipelinestörende Springerei, der 
code ist schneller, länger und passt immer noch in den Speicher. Klingt 
erst mal so also ob nix wesentliches verändert wurde.

Nun sei der Speicher aus mehrerern Speicher-modulen/IC aufgebaut. Und 
man hat aufgepasst das wenn ein beliebiges Modul ausfällt, oder aus 
Stromspargründen (Space) abgeschaltet wird, nichts schlimmes passiert.
Allerdings in der Annahme das die besagte Schleife sich in einem 
Speichermodul komplett befindet und nicht wie durch das loop-unrooling 
mglw. geschehen in zwei.

Dumm gelaufen oder dumm gemacht?

MfG,

von Fpgakuechle K. (Gast)


Lesenswert?

Bernd K. schrieb:
> Fpga Kuechle schrieb:
>> bin ich über den Punkt
>> gestolpert, das verschiedenen  Standards/Zertifizierungen ( im
>> embedded-bereich) verlangen das die maschinelle Optimierung
>> auszuschalten ist (cc -O0).
>
> Das ist ein Widerspruch in sich: In diesen Umfeldern wird gerne auf
> "zertifizierte" Compiler bestanden. Das impliziert daß diese
> vollumfänglich getestet sind und für funktionierend befunden wurden.

Nein, es sind nicht die Überstzungsfehler die man fürchtet sondern man 
spart sich die Arbeit für jeden compiler und Optimierungsstufe zu 
überprüfen ob aus dem C-Code den man gecheckt hat auch was erzeugt wird 
das wiederum OK ist. Bei Optimierung kommt nun mal anderer Code raus 
also andere Speicherbelgung/Laufzeit als ohne Optimierung.

> Die
> Forderung dann trotzdem auf gewisse Optionen dieser "zertifizierten"
> Compiler zu verzichten impliziert daß diese wohl anscheinend doch
> fehlerhaft sein könnten, mithin man sich also den ganzen
> Zertifizierungs-Schmu ebensogut getrost in die Haare hätte schmieren
> können.

Hm, das könnte womöglich sein, wobei es dann nicht 
Compilerzertifizierung an sich unnötig ist sondern nur die 
Zertifizierung der Optimierung. Und die Optimierung wäre ebenfalls 
unnötig. Wäre nicht das erste mal das Compiler feature enthalten die man 
eigentlich nicht will. Aber dann hätte man kein Verkaufsargument um sich 
vom gcc und Mitbewerber abzusetzen.

MfG,

von (prx) A. K. (prx)


Lesenswert?

Fpga Kuechle schrieb:
> Allerdings in der Annahme das die besagte Schleife sich in einem
> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
> mglw. geschehen in zwei.

> Dumm gelaufen oder dumm gemacht?

Hallelujah... das dem Compiler ist die Schuhe zu schieben ist schon 
reichlich vermessen. Bei solcher Auslegung musst du auch bei 
Assembler-Programmierung nach wesentlichen Änderungen das Mapfile 
bemühen. Insbesondere wenn du nicht alleim am Projekt hockst.

Ausserdem pflegen Compiler auch morgen noch den gleichen Code zu 
erzeugen wie heute, wenn man weder das eigene Programm noch den Compiler 
aktualisiert. Und wenn man eine derart empfindliche Umgebung hat, dann 
gehört man doch geteert und gefedert, wenn man den Compiler updatet. Die 
verwendete Compiler-Version sollte als Teil einer isolierten 
Entwicklungsumgebung für genau dieses Projekt auf alle Zeit eingefroren 
werden.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Fpga Kuechle schrieb:
> Allerdings in der Annahme das die besagte Schleife sich in einem
> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
> mglw. geschehen in zwei.

Wer solche Annahmen trifft und glaubt sich darauf verlassen zu können 
und die Betriebssicherheit seines Systems von solchen wackeligen 
Annahmen abhängig macht und das dann obendrein auch noch mit den 
Begriffen "reproduzierbar" oder gar "zertifiziert" in Zusammenhang 
bringt der verdient daß es ihm bei der nächsten Gelegenheit um die Ohren 
fliegt, aber sowas von.

von Nase (Gast)


Lesenswert?

Fpga Kuechle schrieb:
> Ergebnis der Zertifizierung soll die Sicherstellung sein das die
> Software das tut was sie soll und nie was anderes machen kann. (auch
> wenn das andere ergebnismäßig gleich wäre). Diese Überprüfung geschieht
> nun am C-Code, da Assembler oder Hexcode  zu kryptisch und zu lang sind
> als das man ihn 100% verifizieren kann.
Das ist jetzt aber ein Widerspruch in sich.
Bei einer solchen (hanebüchen) Zertifizierung bewertet man doch genau 
das Ergebnis, das die Software produziert. Und das ist stets dasselbe, 
egal wie optimiert wird.
Andernfalls müsste man ja gerade das Assembly zertifizieren.

> Man will ja auch die Funktion
> überprüfen und geht dann davon aus das die 1:1 Umsetzung des Compilers
> passt.
Welche 1:1-Umsetzung denn? Ein C-Compiler ist kein Makroassembler. Es 
gibt keine 1:1-Umsetzung.

> Und um den c-code einfach prüfbar zu halten, schränkt man den noch ein
> (MISRA-C), es darf nicht jedes C-konstrukt verwendet werden.
Ja, MISRA ist eben in vielen Dingen Schwachsinn.
Quelltext wird nicht sicherer, wenn man dem Programmierer Sprachfeatures 
verbietet, die er dann möglicherweise mit noch mehr Gebastel wieder 
umgeht.

> Beispielscenario: loop-unrolling.
>
> Jetz hat man den Code zertififiziert, Programmzeilen gezählt und
> abgeschätzt das es so in den Speicher passt.
Ok, schon der falsche Ansatz. Aber gut, wers braucht.

> Da kommt der Compiler daher
> und optimiert den code durch loop unrooling, er spart sich das dekrement
> des loop-index, den Vergleich  und die pipelinestörende Springerei, der
> code ist schneller, länger und passt immer noch in den Speicher. Klingt
> erst mal so also ob nix wesentliches verändert wurde.
Wurde es ja auch nicht. Die Programmiersprache C wird anhand eines 
abstrakten Automaten mit Seiteneffekten definiert. Jeder, der darin 
irgendetwas Anderes sieht, sollte C nicht verwenden.

> Nun sei der Speicher aus mehrerern Speicher-modulen/IC aufgebaut. Und
> man hat aufgepasst das wenn ein beliebiges Modul ausfällt, oder aus
> Stromspargründen (Space) abgeschaltet wird, nichts schlimmes passiert.
> Allerdings in der Annahme das die besagte Schleife sich in einem
> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
> mglw. geschehen in zwei.
>
> Dumm gelaufen oder dumm gemacht?
Extrem dumm gemacht. Insbesondere bei relokatierenden Linkern, wie gcc 
einer ist.
Wenn du sicherstellen musst, dass ein Stück Quelltext an einer 
besonderen Stelle landet, dann solltest du das im Linkerskript 
festlegen. Alles andere ist wieder Glücksspiel.

von Peter D. (peda)


Lesenswert?

Meiner Meinung nach, ist MISRA nur ein äußerst schwaches Werkzeug, um 
zuverlässige Programme zu erstellen.
Es ist sehr leicht, MISRA konform zu programmieren und trotzdem 
tonnenweise logische Fehler einzubauen.

Z.B. das in MISRA verbotene ?: hat überhaupt kein Fehlerpotential. Im 
Gegenteil, es erlaubt sehr sicheren (Sequence point!) und gut lesbaren 
Code. Es wurde nur verbannt, weil es Anfänger erstmal nachschlagen 
müßten.

Das wichtigste ist, daß man erstmal reichlich Programmiererfahrung bei 
nicht kritischen Anwendungen (Eieruhr, Tamagotchi usw.) gesammelt hat. 
Diese sind durch keine noch so strengen Formalismen zu ersetzen.
Wer Anfänger an sicherheitsrelevanten Code ranläßt, ist automatisch 
Hauptschuldiger am z.B. Flugzeugabsturz oder AKW-Gau.

von Rolf M. (rmagnus)


Lesenswert?

Michael Skropski schrieb:
> Rolf Magnus schrieb:
>> Und woran erkennst du das, bevor so ein Fehler passiert?
>
> Wie soll man was erkennen, was noch garnicht aufgetreten ist?

Gar nicht. Das war mein Punkt. Du sagst, daß du beim Auftreten eines 
Compilerfehlers sofort zu einem anderen, fehlerfreien Compiler wechseln 
würdest. Woher weißt du aber, daß der fehlerfrei ist?

> Wenn ich aber sehe, dass ein Compiler nicht das umsetzt, was ich ihm
> wirklich gesagt habe und für die Erkenntnis vielleicht eine Woche
> verbracht habe, würde ich mir einen anderen Compiler suchen, denn wer
> sagt, dass sowas nicht nochmal vorkommt.

Wer sagt, daß es bei einem anderen Compiler nicht auch vorkommt? Der 
könnte sogar noch mehr Fehler haben als der voherige. Einfach gleich 
beim ersten Fehler wild durchwechseln ist ziemlich unsinnig.
Oder kurz: Du tauschst bekannte Fehler gegen unbekannte. Deshalb wird in 
Bereichen, wo der Code sicher sein muß, nicht einfach mal schnell der 
Compiler gewechselt, auch nicht bei einem Bug im Compiler.

> Wenn ich jemanden überholen will und drücke aufs Gas, das Auto
> beschleunigt aber nicht, werde ich mich schnell nach ein anderem
> umsehen, am besten von einem ganz anderen Hersteller.

Ich nicht. Tatsächlich hatte ich diesen Fall schon mal. Das war eben ein 
Defekt am Motor. Aber ich kauf mir nicht bei jede, Fehler ein neues 
Auto. Abgesehen davon würden einem in so einem Fall irgendwann die 
Hersteller ausgehen.

> Das Vertrauen wäre weg. Das gilt natürlich nicht, wenn ich versehentlich
> ein Tempolimit eingestellt habe. Mit dem Unterschied, dass da mein Leben
> von abhängig sein kann, beim Compiler allerdings eher nicht.

Vielleicht nicht bei dem Code den du schreibst, aber bei dem Code, um 
den es in den hier diskutierten Sicherheitsnormen geht. Sehr viele 
moderne Autos haben zB. E-Gas, d.h. es geht kein Gazsug mehr vom Pedal 
zum Motor, sondern C-Code auf deinem Steuergerät (entweder von Hand 
geschrieben oder aus einem Modell generiert) interpretiert die 
Pedalstellung und entscheidet dann, wieviel Leistung er dem Motor 
abverlangt. Der kann bei einem Fehler auch entscheiden, dir keine 
Motorleistung zu geben, wenn du auf's Gas trittst.

Nase schrieb:
> Gegen (1) hilft tatsächlich nur sauberes Programmieren. Man kann zwar
> die Optimierungen so lange frisieren, bis auch der (semantisch)
> fehlerhafte Programmcode (=fehlendes volatile) korrekt läuft (=Variablen
> nicht herausoptimieren). Und das ist auch leider gängige Praxis. Aber es
> ändert nichts daran, dass der Code fehlerhaft ist und etwas anderes
> beschreibt, als dem Programmierer vorschwebt. Früher oder später rumpelt
> das, pures Glücksspiel.

Es geht eher darum, daß der Code zwar zu funktionieren scheint, man aber 
ein Fehlverhalten trotz Coding-Richtlinien, Reviews und enormen 
Testaufwands nicht gänzlich ausschließen kann. Dessen Wahrscheinlichkeit 
verringert man durch das Abschalten der Optimierungen noch.
Ein Fallschirmspringer hat ja auch noch einen Not-Schirm dabei, obwohl 
am Hauptschirm ja eigentlich nichts sein dürfte.

drama schrieb:
> Wenn ein Programm nur mit -O0 funktioniert und selbst mit -O1 dann nicht
> mehr, weist es i.d.R. auf einen Fehler im Code hin, nicht auf einen
> Fehler des Compilers!

Wenn dein Auto in eine Wand rast, weil das ESP eine Fehlfunktion hat, 
ist dir allerdings relativ egal, ob das durch einen Bug im Compiler oder 
im durch ihn übersetzten Programm passiert ist. Du hättest dir dann eher 
gewünscht, daß an jedem Teil der Kette alles getan worden wäre, um ein 
Fehlverhalten zu vermeiden.

Bernd K. schrieb:
> Das ist ein Widerspruch in sich: In diesen Umfeldern wird gerne auf
> "zertifizierte" Compiler bestanden. Das impliziert daß diese
> vollumfänglich getestet sind und für funktionierend befunden wurden.

Wenn ein Compiler zertifiziert ist, ist er damit nicht automatisch 
fehlerfrei. Es wurde lediglich bestätigt, dass Entwicklung und Test 
(teils sehr aufwändig) nach bestimmten Richtlinien erfolgt ist, durch 
die viele Fehler (vermeintlich) vermieden werden können.

> Jedoch verdienen etablierte Hersteller ordentlich Geld mit dieser Kultur
> der gegenseitigen Beweihräucherung in geschlossener Gesellschaft, völlig
> losgelöst vom praktischen Nutzwert oder irgendeiner Logik, daher ist das
> nun mal einfach so und daran wird auch nicht gerüttelt.

Du würdest also sagen, das das Steuersystem im A380 auch ruhig mit einem 
Compiler übersetzt werden kann, der von irgendeiner Hinterhofklitsche 
geschrieben wurde?
Bei dem hat man übrigens sogar Hard- und Software zweimal entwickeln 
lassen, von verschiedenen Herstellern, mit verschiedenen Komponenten und 
verschiedenen Entwicklungstoolchains, alles zertifiziert.

> Ich als Normalsterblicher nehme gcc und die üblichen Optimierungen, denn
> zum Glück schreibt mir hier keiner vor welche (womöglich suboptimalen)
> Werkzeuge und Einstellungen angeblich besser sein sollen nur weil sie in
> irgendeinem teuren Papier erwähnt werden, ich wähle sie stattdessen nach
> objektiven Kriterien der praktischen Tauglichkeit für den jeweiligen
> Verwendungszweck aus.

Dein Verwendungszweck ist eben ein anderer. Wie würdest du das denn 
sehen, wenn du den Code für dein ESP damit übersetzen müßtest? Lieber 
besser optimieren, damit der Prozessor vielleicht eine nummer kleiner 
ausfallen kann, oder lieber sicherer?

A. K. schrieb:
> Fpga Kuechle schrieb:
>> Allerdings in der Annahme das die besagte Schleife sich in einem
>> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
>> mglw. geschehen in zwei.
>
>> Dumm gelaufen oder dumm gemacht?
>
> Hallelujah... das dem Compiler ist die Schuhe zu schieben ist schon
> reichlich vermessen.

Das hat doch keiner getan.

> Ausserdem pflegen Compiler auch morgen noch den gleichen Code zu
> erzeugen wie heute, wenn man weder das eigene Programm noch den Compiler
> aktualisiert.

Da gibt's grad einen Thread im Forum, der sich damit beschäftigt, daß 
das nicht stimmt. Interessanterweise gibt es offenbar gerade im 
Optimizer von gcc sogar einen Teil, der für die Optimierung einen 
Zufallsgenerator verwendet.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Fpga Kuechle schrieb:
> Stefan Us schrieb:
>> Warscheinlich steckt die Idee dahinter, dass die komplexe Optimierungen
>> eher fehlerhaft sind, als einfache.
>
> Nein, IMHO geht es weniger um Fehler als darum das der Compiler die im
> Quelltext beschrieben Funktion in eine andere überführt als die
> verifiziert wurde.

Ich weiß es selber zwar auch nicht besser, aber Stefans Erklärung
erscheint mir irgendwie plausibler:

Wenn ein Teil (Optimierer) eines komplexen Programms (Compiler) nicht
genutzt wird, werden auch dessen Fehler nicht wirksam.

> Ergebnis der Zertifizierung soll die Sicherstellung sein das die
> Software das tut was sie soll und nie was anderes machen kann.

Mikroskopisch betrachtet tut die kompilierte Software doch fast immer
etwas anderes als im Quelltext steht, weil C-Anweisungen in den
allermeisten Fällen nicht 1:1 auf Prozessorinstruktionen abbildbar sind.
So werden bspw. auf einem 8-Bit-Prozessor aus 1 long-Addition in C 4
Byte-Additionen im erzeugten Maschinencode.

> (auch wenn das andere ergebnismäßig gleich wäre).

Wenn die Ergebnisse ohne und mit Optimierung immer gleich sind, ist doch
alles in Ordnung. Wenn nicht, hat entweder der Programmierer oder der
Optimierer einen Fehler gemacht. Der zweite Fall könnte durch Weglassen
der Optimierungsphase ausgeschlossen werden. Da der erste aber um
Größenordnungen wahrscheinlicher ist, bringt das nicht sehr viel ;-)

> Beispielscenario: loop-unrolling.
>
> ...
>
> Nun sei der Speicher aus mehrerern Speicher-modulen/IC aufgebaut. Und
> man hat aufgepasst das wenn ein beliebiges Modul ausfällt, oder aus
> Stromspargründen (Space) abgeschaltet wird, nichts schlimmes passiert.
> Allerdings in der Annahme das die besagte Schleife sich in einem
> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
> mglw. geschehen in zwei.

Man kann aber auch ohne Loop-Unrolling nicht verhindern, dass die
Schleife an einer Speichermodulgrenze zu liegen kommt, auch wenn die
Wahrscheinlichkeit dafür kleiner ist als mit Loop-Unrolling. Zudem wird
die Schleife meist ja irgendwann wieder verlassen. Spätestens dann wird
das Programm trotzdem in das ausgeschaltete/-fallene Modul hineinlaufen.
Es sei denn, das Programm ist insgesamt so kurz, dass es in ein
einzelnes Speichermodul passt. Das erreicht man aber am ehesten dadurch,
dass man die Optimierung der Programmgröße (beim GCC -Os) nicht aus-,
sondern einschaltet.



Bernd K. schrieb:
> Das ist ein Widerspruch in sich: In diesen Umfeldern wird gerne auf
> "zertifizierte" Compiler bestanden. Das impliziert daß diese
> vollumfänglich getestet sind und für funktionierend befunden wurden.

Das erhofft sich der Kunde, der viel Geld für so einen Compiler ausgibt.

Tatsächlich heißt Sicherheitszertifizierung bei Compilern zunächst
einmal nur, dass sie von einer unabhängigen Organisation (wie bspw. dem
TÜV) auf Konformität zu einem oder mehreren der einschlägigen
Sicherheitsstandards (IEC 61508, ISO 26262, ISO 26262 usw.) sind, wie
dies bspw. bei den IAR-Tools der Fall ist:

  http://www.iar.com/Products/IAR-Embedded-Workbench/Certified-tools-for-functional-safety/Functional-safety-standards/

M.W. legt aber keine der o.g. Normen ein genaues Regelwerk fest, wie ein
Compiler zu prüfen ist, um dessen Konformität festzustellen, da sie sich
ja nicht auf Compiler im Speziellen, sondern auf Systeme und und deren
Software im Allgemeinen beziehen. Der folgende Artikel gibt einen groben
Einblick in diese Problematik:

  http://www.embedded.com/design/prototyping-and-development/4007228/How-to-verify-your-compiler-for-use-in-IEC-61508-safety-critical-applications

Die wesentlichen Punkte, die ich daraus entnehme:

- Die Softwareentwicklung muss nach bestimmten Prozessen ablaufen, wozu
  insbesondere auch eine durchgehende Dokumentation dieser Prozesse
  gehört. Das hilft immerhin dazu bei, im Fehlerfall den Verursacher an
  den Pranger stellen zu können. Vielleicht erhöht das deswegen auch
  etwas die Sorgfalt bei der Entwicklung.

- Es gibt Empfehlungen, die nach Möglichkeit einzuhalten sind. Sind
  diese Empfehlungen aus irgendwelchen Gründen nicht praktikabel, darf
  auch davon abgewichen werden, wenn diese Abweichungen ausreichend
  begründet und dokumentiert werden. Eine solche Abweichung ist bspw.
  schon die Verwendung von C als Programmiersprache: Die allermeisten
  C-Compiler sind nun einmal in C geschrieben und die damit entwickelte
  sicherheitskritische Software logischerweise ebenso.

- Da die korrekte Arbeitsweise des Compilers kaum formal verfiziert
  werden kann, muss sie auf andere Weise ausreichend begründet werden.
  Die Begründung ist dann in Ordnung, wenn sie vom Prüfer akzeptiert
  wird. In dem Artikel wird u.a. "proof-in-use" vorgschlagen, d.h. ein
  länger andauernder fehlerfreier Einsatz des Compilers (oder allgemein
  die sicherheitskritische Software) bei vielen Nutzern wird als Indiz
  für hohe Sicherheit gewertet.

Es gibt sicher noch mehr Kriterien, die von einem zertifizierten
Compiler erfüllt sein müssen. Ich frage mich allerdings, ob das alles
ausreicht, um diesen wirklich sicherer zu machen als bspw. den GCC.
Nimmt man von diesem das jeweils neueste Release des zweitneuesten (und
damit schon etwas gereiften) Branches (derzeit wäre das die Version
4.8.4), ist dank der weiten Verbreitung des GCC und der Unmengen an
Software, die damit bereits kompiliert worden ist, der "proof-in-use"
sicher schon deutlich stärker gegeben als bei einem zertifizierten
Compiler, der auf Grund seines hohen Preises nur von relativ wenigen
Anwendern eingesetzt wird.

Interessant wäre es ja, den Prüfbericht eines zertifizierten Compilers
durchzulesen, um genauer zu erfahren, nach welchen Kriteren da konkret
bewertet wurde. Weiß jemand, ob man als (bspw. IAR-) Kunde Einblick in
einen solchen Bericht bekommt?

von Fpgakuechle K. (Gast)


Lesenswert?

Bernd K. schrieb:
> Fpga Kuechle schrieb:
>> Allerdings in der Annahme das die besagte Schleife sich in einem
>> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
>> mglw. geschehen in zwei.
>
> Wer solche Annahmen trifft und glaubt sich darauf verlassen zu können
> und die Betriebssicherheit seines Systems von solchen wackeligen
> Annahmen abhängig macht und das dann obendrein auch noch mit den
> Begriffen "reproduzierbar" oder gar "zertifiziert" in Zusammenhang
> bringt der verdient daß es ihm bei der nächsten Gelegenheit um die Ohren
> fliegt, aber sowas von.

Den Grund für deine drastischen Worte versteh ich nicht. Das ist hier 
nur ein beispiel das sich Optimierungen auf die Fehlercharakteristik des 
systems auswirken. das ein system von grund auf sicher ist wenn 
loop-unrolling deaktiviert ist habe ich nie behauptet. Von 
reproduzierbar war auch nicht die Rede. Also bitte mehr sachlichkeit.

MfG,

von Fpgakuechle K. (Gast)


Lesenswert?

Yalu X. schrieb:
>> Nun sei der Speicher aus mehrerern Speicher-modulen/IC aufgebaut. Und
>> man hat aufgepasst das wenn ein beliebiges Modul ausfällt, oder aus
>> Stromspargründen (Space) abgeschaltet wird, nichts schlimmes passiert.
>> Allerdings in der Annahme das die besagte Schleife sich in einem
>> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
>> mglw. geschehen in zwei.
>
> Man kann aber auch ohne Loop-Unrolling nicht verhindern, dass die
> Schleife an einer Speichermodulgrenze zu liegen kommt, auch wenn die
> Wahrscheinlichkeit dafür kleiner ist als mit Loop-Unrolling. Zudem wird
> die Schleife meist ja irgendwann wieder verlassen. Spätestens dann wird
> das Programm trotzdem in das ausgeschaltete/-fallene Modul hineinlaufen.
> Es sei denn, das Programm ist insgesamt so kurz, dass es in ein
> einzelnes Speichermodul passt.

Loop unrolling ist ja hier nur ein Beispiel das man Eigenschaften die 
man aus dem C-Quelltext zieht nicht mehr auf das Compilat zutreffen

> Das erreicht man aber am ehesten dadurch,
> dass man die Optimierung der Programmgröße (beim GCC -Os) nicht aus-,
> sondern einschaltet.

Dann verste ich das Optimierungskonzept anders, also wenn Optimierung 
aus -O0 wird dennoch loop-unrolling betrieben?
Bei Sizeoptimierung bleibt es im wesentlichen bei dem selben Problem: 
Eigenschaften die aus dem Quelltext gezogen werden wie Größe 
Daten/Codesegment stimmen nicht mit dem Kompilat überein, beispielsweise
Strings zusammenfassen.
const char[] str_message_ok "KEIN FEHLER";
const char[] str_message_nok "EIN FEHLER";


Zertifizierung funktioniert eben leider indirekt. Es sollen 
Eigenschaften des Programm als das binary bewertet werden. Betrachtet 
wird aber der Quelltext. Also muß man dem Compiler  alle Freiheitsgrade 
nehmen damit er den code 1:1 übersetzt.

MfG,

von Fpgakuechle K. (Gast)


Lesenswert?

A. K. schrieb:
> Fpga Kuechle schrieb:
>> Allerdings in der Annahme das die besagte Schleife sich in einem
>> Speichermodul komplett befindet und nicht wie durch das loop-unrooling
>> mglw. geschehen in zwei.
>
>> Dumm gelaufen oder dumm gemacht?
>
> Hallelujah... das dem Compiler ist die Schuhe zu schieben ist schon
> reichlich vermessen.

Nee, ich sach nich der Compiler is schuld. Schuld ist das prinzip das 
Programm anhand seines Sources zu Prüfen und nicht am Compilat.
Und das ist auch kein Fehler sondern eine Frage der Machbarkeit.
Am Compilat die Fehlerfrfeiheit zu prüfen ist IMHO hoffnungsloser als 
die Prüfung am C-Quelltext.

> Bei solcher Auslegung musst du auch bei
> Assembler-Programmierung nach wesentlichen Änderungen das Mapfile
> bemühen. Insbesondere wenn du nicht alleim am Projekt hockst.

Ist Begutachtung des Map-files Bestandteil der Zertifizierung?
Ist der Compiler/Assembler bezüglich des Wahrheitsgehaltes seines map- 
reports zertifiziert?

>
> Ausserdem pflegen Compiler auch morgen noch den gleichen Code zu
> erzeugen wie heute, wenn man weder das eigene Programm noch den Compiler
> aktualisiert. Und wenn man eine derart empfindliche Umgebung hat, dann
> gehört man doch geteert und gefedert, wenn man den Compiler updatet. Die
> verwendete Compiler-Version sollte als Teil einer isolierten
> Entwicklungsumgebung für genau dieses Projekt auf alle Zeit eingefroren
> werden.

Volle Zustimmung.

MfG,

von (prx) A. K. (prx)


Lesenswert?

Fpga Kuechle schrieb:
> Ist Begutachtung des Map-files Bestandteil der Zertifizierung?

Ich habe keine Ahnung von solchen Zertifizierungen. Aber mit 
Zertifizerungen kann man kein Hirn ersetzen.

Wenn eine strikte Adressvergabepolitik Teil der Anwendung ist, dann muss 
eine Kontrolle der Adressvergabe Teil der Entwicklung sein. Notfalls per 
Kontrollprogramm, dass an deiner Statt ins Mapfile guckt, oder 
wasweissich wohin. Unabhängig von irgendwelchen offiziellen Stempeln.

: Bearbeitet durch User
von Fpgakuechle K. (Gast)


Lesenswert?

Yalu X. schrieb:
> Interessant wäre es ja, den Prüfbericht eines zertifizierten Compilers
> durchzulesen, um genauer zu erfahren, nach welchen Kriteren da konkret
> bewertet wurde. Weiß jemand, ob man als (bspw. IAR-) Kunde Einblick in
> einen solchen Bericht bekommt?

Da wüsst ich auch gern. Mir ist ein Fall bekannt in dem der Hersteller 
dem Kunden angeboten hat die CPU und Compiler gemeinsam zu 
zertifizieren, wenn sich der Kunde für diese CPU entscheidet. Hat man 
aber nicht, also war auch nix mit Zertifizierung.

Der Kunde war R&S, zertifiziert werden sollte nach DO-178 o.ä..

MfG,

von Nase (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Es geht eher darum, daß der Code zwar zu funktionieren scheint, man aber
> ein Fehlverhalten trotz Coding-Richtlinien, Reviews und enormen
> Testaufwands nicht gänzlich ausschließen kann. Dessen Wahrscheinlichkeit
> verringert man durch das Abschalten der Optimierungen noch.
> Ein Fallschirmspringer hat ja auch noch einen Not-Schirm dabei, obwohl
> am Hauptschirm ja eigentlich nichts sein dürfte.
Nein, überhaupt nicht. Eher im Gegenteil: Durch Optimierungen fallen 
Fehler eher auf. Ganz einfach, weil das, was man hinprogrammiert hat, 
quasi aus unterschiedlichen Blickwinkeln übersetzt wird. Wenn mit 
Optimierung "1" läuft und mit Optimierung "2" nicht mehr, dann sucht man 
mit sehr großer Wahrscheinlichkeit ein latentes Problem in seiner 
Anwendung.

Deine Argumentation könnte man ja genauso auch so lesen: Der Optimierer 
verringert das erzeugte Codevolumen (erheblich). Also wird auch weniger 
Code ausgeführt, der Fehler haben könnte...

Rolf Magnus schrieb:
> Du würdest also sagen, das das Steuersystem im A380 auch ruhig mit einem
> Compiler übersetzt werden kann, der von irgendeiner Hinterhofklitsche
> geschrieben wurde?
Nein, sicher will er das nicht. Er will nur sagen, dass solche 
Zertifizierungen objektiv ziemlich grenzwertig sind. Auch meine Meinung 
ist, dass solch eine Zertifizierung kurz über Antivirenprogrammen 
rangiert. Wie soll man einen Compiler denn auch zertifizieren? Oder 
was soll man überhaupt zertifizieren? Den Quelltext des Compilers wird 
man ganz sicher nicht verifizieren können, schon aufgrund seines 
Umfangs. Also bleibt nur, etwas Testcode reinzustecken und zu gucken, 
was herauskommt. Also im Prinzip etwas total praxisfernes für einen 
Einzelfall zu machen und einen Stempel dranzumachen.
Das ist ungefähr so, wie einen Compiler mit einer Endlosschleife zu 
benchmarken.

Der Internet-Explorer ist auch TÜV-Zertifiziert. Auf Heise-Newsticker 
damals stand die Meldung von der Zertifizierung des IE gleich unter 
einer neuen Sicherheitslücke im IE.

> Bei dem hat man übrigens sogar Hard- und Software zweimal entwickeln
> lassen, von verschiedenen Herstellern, mit verschiedenen Komponenten und
> verschiedenen Entwicklungstoolchains, alles zertifiziert.
Und solche Diversität ist m.M.n. der einzig tragbare Ausweg aus dem 
Dilemma. Das macht jede Sicherheitssteuerung heute so.

Rolf Magnus schrieb:
> Dein Verwendungszweck ist eben ein anderer. Wie würdest du das denn
> sehen, wenn du den Code für dein ESP damit übersetzen müßtest? Lieber
> besser optimieren, damit der Prozessor vielleicht eine nummer kleiner
> ausfallen kann, oder lieber sicherer?
Auch das basiert wieder auf der fragwürdigen Annahme, dass ein 
Optimierer den Code potentiell fehlerträchtiger macht.

Wenn ich etwas für ein ESP übersetzen müsste, dann würde ich mir alle 
greifbaren Compiler für die Zielarchitektur nehmen und den Quelltext in 
allen Compilern mit allen Optimierungsstufen (oder sonstigen 
Einstellungen derart) testen. Damit finde ich mehr Fehler, als den 
Optimierer pauschal abzustellen.

Der Optimierer ist ja auch nur ein kleiner Teil. Würdest du deinen 
Quelltext dann auch nicht modulweise übersetzen, sondern alles 
zusammenkopieren? Linker und Präprozessor können auch Fehler machen.


Yalu X. schrieb:
> Mikroskopisch betrachtet tut die kompilierte Software doch fast immer
> etwas anderes als im Quelltext steht, weil C-Anweisungen in den
> allermeisten Fällen nicht 1:1 auf Prozessorinstruktionen abbildbar sind.
Du brauchst soweit garnicht zu gehen. Das ist die abstrakte Maschine, 
die ich oben erwähnte.
Als Beispiel folgende beiden Programmstücke:
1
fputs("abc", stdout);
und
1
putchar('a');
2
putchar('b');
3
putchar('c');
Wie bewertest du die nun?
Strenggenommen könnte der Compiler aus beiden Programmen denselben 
Maschinencode erzeugen. Denn beide Programme verhalten sich exakt 
identisch. Das liegt eben daran, dass die Sprache C anhand einer 
abstrakten Maschine definiert ist und ihr Verhalten sich in der Wirkung 
nach außen manifestiert. Beide obigen Programme geben 'abc' aus. Wie der 
Compiler das bewerkstelligt, ist ihm überlassen. Er könnte die drei 
putchar-Aufrufe legitim zu einem fputs-Aufruf zusammenziehen, ohne das 
Programm zu verändern.

Das ist im Übrigen dann auch das Problem der meisten Anwendungen. Damit 
ich mit dieser Sprachdefinition klarkomme, müssen fputs und putchar 
natürlich hinreichend eintrittsinvariant, also frei von Seiteneffekten 
sein (was sie laut Standard auch sind). Code in Applikationen ist das 
oft nicht.

Yalu X. schrieb:
> Weiß jemand, ob man als (bspw. IAR-) Kunde Einblick in
> einen solchen Bericht bekommt?
Papier ist geduldig.


Fpga Kuechle schrieb:
> Den Grund für deine drastischen Worte versteh ich nicht. Das ist hier
> nur ein beispiel das sich Optimierungen auf die Fehlercharakteristik des
> systems auswirken.
Naja, er hat ein drastisches Problem bemängelt.
Dein Beispiel scheitert nicht ander Fehlercharakteristik des Systems, 
sondern schon einfach an der Fehlbedienung der Toolchain. Wenn 
irgendetwas dafür verantwortlich ist, wo Code landet, dann /ganz 
sicher nicht/ der Optimierer.
Die Optimierungen abzuschalten sind ein primitives Mittel, um einen 
besseren Zusammenhang zwischen Quelltext und Assembly hinzubekommen. 
Darum möchte man beim Debuggen ja auch nicht optimieren, weil man dann 
nur schwer Zeile für Zeile durchschreiten kann. Aber Optimierungen 
abzuschalten ist definitiv das falsche Mittel, um Code im Speicher zu 
platzieren - dafür ist der Linker verantwortlich.

Leider sieht man das halt oft: Die Programmierer wissen nichts über 
volatile oder sind zu bequem, also schaltet man pauschal die Optimierung 
aus...



Letztlich bleibt die wesentliche Frage, ob man pauschal Fehler 
vermeidet, wenn man Teile des Compilers (den Optimierer) nicht nutzt und 
so weniger Code im Compiler beansprucht.
Ich denke nach wie vor: Nein.

von Fpgakuechle K. (Gast)


Lesenswert?

Rolf Magnus schrieb:


>> Ausserdem pflegen Compiler auch morgen noch den gleichen Code zu
>> erzeugen wie heute, wenn man weder das eigene Programm noch den Compiler
>> aktualisiert.
>
> Da gibt's grad einen Thread im Forum, der sich damit beschäftigt, daß
> das nicht stimmt. Interessanterweise gibt es offenbar gerade im
> Optimizer von gcc sogar einen Teil, der für die Optimierung einen
> Zufallsgenerator verwendet.

Also bei FPGA's ist das zuweilen üblich, anderer Lauf, anderes Ergebnis. 
Ursache dafür ist das bei dem routing der Logicelemente Probleme 
(floorplanning) ähnlich des Traveling salesman zu lösen ist.

Dafür nimmt man Lösungsverfahren wie simulated anealing. Und simulated 
annealing fängt in der ersten Iteration mit einer ausgewürfelten Lösung 
an.

http://de.wikipedia.org/wiki/Simulated_annealing

MfG,

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

A. K. schrieb:
> Ausserdem pflegen Compiler auch morgen noch den gleichen Code zu
> erzeugen wie heute, wenn man weder das eigene Programm noch den Compiler
> aktualisiert.
Wenn das so einfach ist, dann frag ich mich, was die Leute bei Debian 
(und auch wir, in der Firma) fuer Probleme beim Thema: "Rebuild 
Sicherheit" haben. Ist ja alles ganz einfach, wenn es nach dir geht.
http://www.golem.de/news/softwaresicherheit-vertrauen-durch-reproduzierbare-build-prozesse-1502-112092.html
Da scheint naemlich ne ganze Menge mehr rein zu spielen, als nur der zu 
ubersetzende Code und die Compilerversion.

Aber bestimmt sind die Leute bei Debian einfach nur zu dumm...

Just my 2 cent...

von (prx) A. K. (prx)


Lesenswert?

Rolf Magnus schrieb:
> Da gibt's grad einen Thread im Forum, der sich damit beschäftigt, daß
> das nicht stimmt. Interessanterweise gibt es offenbar gerade im
> Optimizer von gcc sogar einen Teil, der für die Optimierung einen
> Zufallsgenerator verwendet.

Yep. Aber der Einfluss auf das Adresslayout des direkt erzeugten Codes 
dürfte gering bis nicht nicht existent sein. Einflüsse der Reihenfolge 
vom Linker sind ruppiger. Das muss man selber durch explizite 
Reihenfolge ausschliessen. Sonst ist man ohnehin geliefert.

Im Steuerungsbereich bin ich zudem ein grosser Fan deterministischer 
Compiler. Es stört mich kein Bisschen, wenn SPECmark-Fans davon 
profitieren, aber embedded sollten Compiler m.E. konservativer arbeiten. 
Wenn ein Compiler mit nichtdeterministischer Codeerzeugung tatsächlich 
ein Zertifikat für kritische Embedded-Entwicklung kriegen kann, dann 
würde ich den Sinn solcher Zertifikate im Ersatz von Klopapier sehen.

von (prx) A. K. (prx)


Lesenswert?

Kaj G. schrieb:
> Aber bestimmt sind die Leute bei Debian einfach nur zu dumm...

Andere Umgebung, anderes Entwicklungsziel. Ich beziehe mich hier auf 
Entwicklung im Embedded Umfeld, verschärft noch durch Kuechles 
Adressvergabeproblem. Das ist schon ein wenig anders als die üblichen 
Debian-Builds. Hoffe ich jedenfalls.

Wenn sich aber herausstellen sollte, dass beim nächste Airbus Debian am 
Steuer sitzt, dann ist's aus mit der Lust am Fliegen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Fpga Kuechle schrieb:
> Dann verste ich das Optimierungskonzept anders, also wenn Optimierung
> aus -O0 wird dennoch loop-unrolling betrieben?

Nein, Loop-Unrolling ist defaultmäßig nur bei -O3 aktiviert. -Os liefert
aber unabhängig davon meist kürzeren Code als -O0, weil ja auch noch
andere Dinge optimiert werden.

> Bei Sizeoptimierung bleibt es im wesentlichen bei dem selben Problem:
> Eigenschaften die aus dem Quelltext gezogen werden wie Größe
> Daten/Codesegment stimmen nicht mit dem Kompilat überein, beispielsweise
> Strings zusammenfassen.
> const char[] str_message_ok "KEIN FEHLER";
> const char[] str_message_nok "EIN FEHLER";

Zumindest der GCC fasst gleiche Strings-Literale auch schon bei -O0
zusammen¹. Diesbezüglich wäre ein Verbot der Optimierung also nutzlos.
Generell wird auch bei -O0 mehr optimiert, als man vielleicht erwarten
würde. So werden bspw. konstante Teilausdrücke ausgewertet. Weil der
Compiler dies in einigen Situationen sowieso tun muss, tut er es an
allen anderen Stellen eben auch. Ebenso werden bei -O0 teilweise
arithmetische Ausdrücke umgestellt, wenn ein dadurch entstehender
Vorteil durch den Compiler ohne viel Aufwand erkennbar ist.

Manchmal hilft das Einschalten der Optimierung sogar beim Aufdecken von
Programmfehlern, bspw. von uninitialisierten Variablen. Um diese zu
finden, muss der Compiler eine Datenflussanalyse machen, was er aber nur
im Rahmen der Optimierung tut.

Ich kann deswegen trotz deiner gut gemeinten Begründungsversuche
wirklich nicht erkennen, was an nichtoptimierten Code besser sein soll
als an optimierten, solange letzterer nicht auf Grund von Bugs im
Optimierer fehlerhaft ist.

Was in den jeweiligen Optimierungsstufen (einschließlich ausgeschalteter
Optimierungsstufen) tatsächlich optimiert wird, hängt sehr stark vom
verwendeten Compiler ab. Deswegen sollten vielleicht diejenigen, die die
Optimierung verteufeln (wer auch immer die sein mögen), dies nicht
pauschal tun, sondern genau spezifizieren, welche Arten der Optimierung
aus welchen Gründen ihrer Meinung nach böse sind.

—————————
¹) ... wenn auch nicht in deinem Beispiel, weil dort die String nicht
   exakt gleich sind und zudem zwei unterschiedliche Variablen damit
   belegt werden.

von Rolf M. (rmagnus)


Lesenswert?

Nase schrieb:
> Deine Argumentation könnte man ja genauso auch so lesen: Der Optimierer
> verringert das erzeugte Codevolumen (erheblich). Also wird auch weniger
> Code ausgeführt, der Fehler haben könnte...

Dass man die Fehlerwahrschienlichkeit durch bloße Verringerung der 
Anzahl der Maschinen-Instruktionen nicht drücken kann, sollte ja wohl 
klar sein.
Es geht hier darum, ganze Module eines Programms komplett nicht zu 
nutzen. Das ist dann doch nochmal was anderes.

Nase schrieb:
> Rolf Magnus schrieb:
>> Dein Verwendungszweck ist eben ein anderer. Wie würdest du das denn
>> sehen, wenn du den Code für dein ESP damit übersetzen müßtest? Lieber
>> besser optimieren, damit der Prozessor vielleicht eine nummer kleiner
>> ausfallen kann, oder lieber sicherer?
> Auch das basiert wieder auf der fragwürdigen Annahme, dass ein
> Optimierer den Code potentiell fehlerträchtiger macht.

Ich finde die nicht so fragwürdig. Ohne Optimierer werden einige Teile 
des Compilers, die besonders intensiv am generierten Code rumfuhrwerken, 
nicht genutzt. Dass sich das Potenzial für Fehler dadurch verringert, 
liegt meines Erachtens auf der Hand.

> Wenn ich etwas für ein ESP übersetzen müsste, dann würde ich mir alle
> greifbaren Compiler für die Zielarchitektur nehmen und den Quelltext in
> allen Compilern mit allen Optimierungsstufen (oder sonstigen
> Einstellungen derart) testen.

Das kann man ja von mir aus während der Entwicklung machen - und danach 
den Optimizer ausschalten. Denn auch mit deiner Methode wird man nicht 
alle Fehler finden können. Und wenn nur ein Fehler drin ist (egal ob im 
Compiler oder im Code), der ohne Optimierung keine singifikante 
Auswirkung hat, dann hat sich's schon gelohnt.

> Der Optimierer ist ja auch nur ein kleiner Teil. Würdest du deinen
> Quelltext dann auch nicht modulweise übersetzen, sondern alles
> zusammenkopieren? Linker und Präprozessor können auch Fehler machen.

Die korrekte Funktion eines Linkers nachzuweisen, sollte aber deutlich 
leichter sein als die des Compilers.

von Fpgakuechle K. (Gast)


Lesenswert?

Yalu X. schrieb:
> Fpga Kuechle schrieb:

>> Bei Sizeoptimierung bleibt es im wesentlichen bei dem selben Problem:
>> Eigenschaften die aus dem Quelltext gezogen werden wie Größe
>> Daten/Codesegment stimmen nicht mit dem Kompilat überein, beispielsweise
>> Strings zusammenfassen.
>> const char[] str_message_ok "KEIN FEHLER";
>> const char[] str_message_nok "EIN FEHLER";

> —————————
> ¹) ... wenn auch nicht in deinem Beispiel, weil dort die String nicht
>    exakt gleich sind und zudem zwei unterschiedliche Variablen damit
>    belegt werden.

Ist dem so? Ich meine mal gelesen zu haben das manche compiler in diesem 
Fall nur einen String ablegen, und dann etweder auf das erste Zeichen 
'K' für den längeren String und für den kürzeren auf 'E' als 
Stringanfang. Nannte sich string merging oder ähnlich.

MfG,

von (prx) A. K. (prx)


Lesenswert?

Rolf Magnus schrieb:
> Die korrekte Funktion eines Linkers nachzuweisen, sollte aber deutlich
> leichter sein als die des Compilers.

Seit Compiler einen Teil ihrer Arbeit dorthin verlagern, damit besser 
optimiert werden kann, nimmt die Komplixität von Linker recht heftig zu.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Fpga Kuechle schrieb:
> Ist dem so? Ich meine mal gelesen zu haben das manche compiler in diesem
> Fall nur einen String ablegen, und dann etweder auf das erste Zeichen
> 'K' für den längeren String und für den kürzeren auf 'E' als
> Stringanfang.

Hast recht, es werden auch String-Literale, von denen das eine ein
Suffix des anderen ist, optimiert. Das macht aber dann der Linker, und
der auch nur mit eingeschalteter Optimierung. Beispiel:
1
#include <stdio.h>
2
3
const char *str_message_ok  = "KEIN FEHLER";
4
const char *str_message_nok =  "EIN FEHLER";
5
6
int main(void) {
7
  printf("%td\n", str_message_nok - str_message_ok);
8
  return 0;
9
}

Ohne Optimierung -> 12
Mit  Optimierung ->  1

Lässt man das 'K' im ersten String weg, gibt das Programm auch ohne
Optimierung 0 aus, d.h. die beiden Pointer zeigen auf dasselbe Objekt.

: Bearbeitet durch Moderator
von Fpgakuechle K. (Gast)


Lesenswert?

Ich geh grad durch die Release Notes vom IAR für MSP430  durch:
http://www.iarsys.co.jp/products/ew430-5401-infocenter/icc430.ENU.html

Auszug:

1.11A 1997-09-11
C0007
Illegal optimization for assignments of type 'uint = uchar;' has now 
been removed.
--
1.22A 1999-11-25

    C0013
    Optimization level 3 now generates fully debuggable code.

-> Interessant, funktioniert zwar auch mit Optimierung ist aber nicht 
mehr voll "debugbar"
--
1.25A 2001-11-09
C00020
The optimizer corrupted local pointers at higher optimizations than -s6, 
when decrementing more than twice. This has now been corrected.
--
v 4.11B - 2008-07-10
In some cases, the assembler-level peephole optimizer could incorrectly 
rewrite code when mixing byte and word accesses to the same location in 
memory.

--
Version 5.30.1 2011-06-30
EW22422: In special circumstance, an AND.W #1, Rx instruction is no 
longer incorrectly optimized away.

Finde ich jetzt nicht besonders vertrauenserweckend, aber vielleicht ist 
der IAR eine schlechte Referenz.

MfG

von Bernd K. (prof7bit)


Lesenswert?

Rolf Magnus schrieb:
> Du würdest also sagen, das das Steuersystem im A380 auch ruhig mit einem
> Compiler übersetzt werden kann, der von irgendeiner Hinterhofklitsche
> geschrieben wurde?

Nein, da sollte man natürlich den breit getesteten und bewährten gcc 
nehmen und nicht den Compiler einer zertifizierten Hinterhofklitsche.

von (prx) A. K. (prx)


Lesenswert?

Fpga Kuechle schrieb:
> Ich geh grad durch die Release Notes vom IAR für MSP430  durch:

Lies dir mal die Errata eines aktuellen Intel-Prozessors durch und 
überlege, was man damit alles macht. Da wird dir vmtl. Angst und Bange 
und du wechselst stante pede auf RasPi (weil's dessen Errata nicht 
öffentlich gibt, also sind wohl auch keine drin ;-).

Nützt nämlich nichts, wenn Programmierer und Compiler alles richtig 
machen, aber die Maschine Mist baut.

: Bearbeitet durch User
von Fpgakuechle K. (Gast)


Lesenswert?

A. K. schrieb:
> Fpga Kuechle schrieb:
>> Ich geh grad durch die Release Notes vom IAR für MSP430  durch:
>
> Lies dir mal die Errata eines aktuellen Intel-Prozessors durch und
> überlege, was man damit alles macht.

Ja hab ich gemacht und da steht:


"Intel products are not intended for use in medical, life saving, life 
sustaining, critical control or safety
systems, or in nuclear facility applications."

http://www.intel.es/content/dam/www/public/us/en/documents/design-guides/celeron-400-guide.pdf

Und da ich davon ausgehe, das bspw. die Medizintechnikfirmen nur dann 
certifiziert werden wenn sie solche produkte aussparen, kann ich völlig 
beruhigt das erata lesen und aus Fehlern anderer lernen.

MfG,

von (prx) A. K. (prx)


Lesenswert?

Und du meinst, für jene Prozessoren und Systeme, denen du dich 
bedenkenlos anvertraust, existiert keine solche Liste?

von Fpgakuechle K. (Gast)


Lesenswert?

Fpga Kuechle schrieb:

> "Intel products are not intended for use in medical, life saving, life
> sustaining, critical control or safety
> systems, or in nuclear facility applications."

Hm, also irgendwie schau ich da nicht völlig durch. Hier ein 
Medizintechnik-board mit intel:

http://www.medizin-und-elektronik.de/elektronik-in-der-klinik/article/103617/0/Medical-Motherboards_mit_Core_i-Prozessoren/

Aber vielleicht ist ein CT mit diesem Board keine Medizintechnik im 
Sinne von

"medical, life saving, life
sustaining, critical control or safety
systems, or in nuclear facility applications"???

von (prx) A. K. (prx)


Lesenswert?

NB: Solche Errata Sheets, oder etwas in der Art, gibts auch für Brücken 
und andere nicht gänzlich ungefährlichen Infrastrukturkomponenten. Und 
mit dem Alter werden die immer länger und länger.

Aber das ist natürlich alles brav zertifiziert - d.h. jemand nickt es ab 
und alle hoffen, dass der olle Kram noch so lange hält bis wieder Geld 
in der Kasse oder jemand anderes dafür verantwortlich ist.

von Fpgakuechle K. (Gast)


Lesenswert?

A. K. schrieb:
> Und du meinst, für jene Prozessoren und Systeme, denen du dich
> bedenkenlos anvertraust, existiert keine solche Liste?

Und wo soll uns diese Diskussion über die Errate-liste hinführen?

Ich halte nichts davon Compilerfehler unbeachtet zu lassen weil Hardware 
auch nicht perfekt ist.

MfG,

PS: 
http://www.baaske-medical.de/media/content/DerPC_keinMedizinprodukt.pdf

klingt interessant - wird heute meine Bettlektüre.

von Bernd K. (prof7bit)


Lesenswert?

Fpga Kuechle schrieb:
> Fpga Kuechle schrieb:
>
>> "Intel products are not intended for use in medical, life saving, life
>> sustaining, critical control or safety
>> systems, or in nuclear facility applications."
>
> Hm, also irgendwie schau ich da nicht völlig durch. Hier ein
> Medizintechnik-board mit intel:
>
> 
http://www.medizin-und-elektronik.de/elektronik-in-der-klinik/article/103617/0/Medical-Motherboards_mit_Core_i-Prozessoren/

Das ist nur für die Anwälte. Insbesondere in den USA, dem Land der 
unbegrenzten Schadensersatzklagen. Damit kann man sich prophylaktisch 
aus jeglicher Verantwortung stehlen und den schwarzen Peter elegant an 
das nächste Opfer (oder den nächsten Täter) in der Supply-Chain 
weiterreichen. Dumm dran ist nur derjenige der vergessen hat sowas ins 
Kleingedruckte seines Produktdatenblattes zu schreiben oder der gar 
keine Gelegenheit dazu hatte weil er zufällig der Endverbraucher ist.

: Bearbeitet durch User
von Nase (Gast)


Lesenswert?

Yalu X. schrieb:
> #include <stdio.h>
>
> const char *str_message_ok  = "KEIN FEHLER";
> const char *str_message_nok =  "EIN FEHLER";
>
> int main(void) {
>   printf("%td\n", str_message_nok - str_message_ok);
>   return 0;
> }
Man sollte aber anmerken, dass dieser Code (abseits der Demonstration) 
fehlerhaft ist.

von Freddie (Gast)


Lesenswert?

Fpga Kuechle schrieb:
> Und da ich davon ausgehe, das bspw. die Medizintechnikfirmen nur dann
> certifiziert werden wenn sie solche produkte aussparen, kann ich völlig
> beruhigt das erata lesen und aus Fehlern anderer lernen.

Ha-ha!

Glaub das mal ruhig weiter... du würdest dich wundern, wo überall der 
Atom drinsteckt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Nase schrieb:
> Man sollte aber anmerken, dass dieser Code (abseits der Demonstration)
> fehlerhaft ist.

Ohne jetzt diesen Thread zu sehr ins Offtopic ziehen zu wollen: Verrätst
du vielleicht kurz, wo der Fehler liegt?

Ich kann ihn trotz mehrfachen Durchlesens nicht finden, lerne aber gerne
noch etwas hinzu.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Ohne jetzt diesen Thread zu sehr ins Offtopic ziehen zu wollen: Verrätst
> du vielleicht kurz, wo der Fehler liegt?

Subtraktion von Pointern auf verschiedene Objekte. Du darfst nur Pointer 
auf das gleiche Objekt subtrahieren.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

A. K. schrieb:
> Subtraktion von Pointern auf verschiedene Objekte.

Ah ja, danke, jetzt hat's geschnackelt :)

Dann macht also in diesem Fall das Einschalten der Optimierung aus
fehlerhaftem Code korrekten Code, oder? ;-)

Aber ich glaube, das ist eher eine philosophische Frage, für die wir,
falls sie jemand diskutieren möchte, einen neuen Thread aufmachen
sollten.

von Fpgakuechle K. (Gast)


Lesenswert?

Vielen Dank für die interessante Diskussion. Beim Durcharbeiten von 
Literatur zur DO-254 (sichere komplexe Elektronik im Flieger) bin ich 
auf folgende Darstellung gestoßen, die m.E. die hier angerissenen 
Probleme von Optimierenden Compilern gut zusammanfasst. (aus 
978-1-4822-0605-0)


... capability/complexity - Dichotomy : 
(Leistungsfähigkeit/Komplexitäts) -Zweiteilung

 leistungsfähigere (capability) tools sind mit einer höheren Komplexität 
(complexity) verbunden was wiederum zu einer Erhöhung der Unsicherheit 
(uncertainty) führt.

 Wesentliche Ziel bei der Entwicklung von sicherer designs ist die 
Verringerung der Unsicherheit bis zu beherrschbaren Maß ("to reduce 
uncertainty to managable levels")

Deshalb muss mit jeder baugruppe, tool, design-feature oder design 
methode die das Potential für Unsicherheit erhöht in abwägender und 
überlegter Weise  umgegangen werden
("needs to be dealt with in a deliberate manner")

Dazu passen folgende Roys Regeln die an anderer Stelle als Kleines 1x1 
des sicheren Entwurfes gelistet werden:

-> "Make your design bulletproof even if no one is shooting at it"
-> "Do not ask for trouble (Avoidance is better than mitigation)"
-> "There is no hope ("We should never hope that our designs are safe, 
we should only know it for fact"

Mein Fazit aus dieser Betrachtung ist:
Optimierungen erhöhen die Wahrscheinlichkeit für Fehler (oder 
"Fehl-Optimierungen") bei der Code-Übersetzung.
dem muß man angepasst entgegen wirken. Die radikalste Variante ist der 
Verzicht/Verhinderung von Automatischer Optimierung.

MfG,

von Stefan F. (Gast)


Lesenswert?

Äh ja, das wurde schon geschrieben.

von Fpgakuechle K. (Gast)


Lesenswert?

Stefan Us schrieb:
> Äh ja, das wurde schon geschrieben.

Ja aber IMHO nicht so stringent als:

Wesentliche Ziel bei der Entwicklung von sicherer Designs ist die
Verringerung der Unsicherheit bis zu beherrschbaren Maß ("to reduce
uncertainty to managable levels")

Und nicht mit belastbarer Quellenangabe mit Bezug auf einen etablierten 
Standard.


MfG,

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> A. K. schrieb:
>> Subtraktion von Pointern auf verschiedene Objekte.
>
> Ah ja, danke, jetzt hat's geschnackelt :)
>
> Dann macht also in diesem Fall das Einschalten der Optimierung aus
> fehlerhaftem Code korrekten Code, oder? ;-)

Der Code hat Undefined Behaviour, egal was der Compiler draus macht oder 
was du als Ergebnis erwartest.

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.