Forum: Compiler & IDEs Neuer gcc compiler für ARM und Optimierungen


von Malte _. (malte) Benutzerseite


Angehängte Dateien:

Lesenswert?

Mit dem Wechsel von Debian 11 auf Debian 12 wurde auch der gcc für ARM 
aktualisiert (jetzt arm-none-eabi-gcc (15:12.2.rel1-1) 12.2.1 20221205).
Leider liefen damit einige meiner Projekte nicht mehr. Also hab ich die 
Ursache eingegrenzt und bin auf eine Optimierung gestoßen, die dafür 
sorgt, dass meine eigene strlen Implementierung mit der Optimierung von 
Os durch eine Endlosschleife ersetzt wird:

Aus
1
size_t strlen(const char * text) {
2
  size_t len = 0;
3
  while(*text) {
4
    text++;
5
    len++;
6
  }
7
  return len;
8
}

wird mit -Os:
1
strlen:
2
b strlen

Benenne ich meine Funktion um, so wird daraus ebenfalls b strlen.
Der Compiler erkennt also dass meine Implementierung das selbe liefert 
wie strlen und will meine Funktion durch einen Aufruf der Standardlib 
ersetzen. Wie schalte ich das ab? Die Makefile fürs Beispiel habe ich 
angehängt. Mit O1 sieht der generierte Code gut aus. Mit O2 wird ein 
rekursiver Aufruf mit fehlerhaften Rückgabewert draus.

Bevor jetzt jemand fragt warum ich die Standard strlen Funktion ersetze: 
Meine Implementierung ist zwar nicht unbedingt schneller, aber deutlich 
Programmspeicher sparender als die strlen der newlib (28byte vs 
220byte).

von Motopick (motopick)


Lesenswert?

Mein Vertrauen in den GCC und die Maintainer ist schon lange gestoert.

Ein AVR-GCC verweigerte, ohne weitere Fehlermeldung die Compileroption 
-Os.
Nach vielem Suchen stellte sich heraus, dass dieser Teil eine bessere
CPU im Host erwartete...
Eine Qualitaetskontrolle hat da sicher nicht stattgefunden.
GCC scheint halt "Bastlersoftware" zu sein.

Oder das fuer eine Compilerversion X valider Code, in der 
Compilerversion
X+1, sich nur noch als "grosser Haufen von Fehlern" praesentiert.
Und man bevor man weitere Zeit verschendet, die Distribution mit
Version X in einen Virtualisierer installiert, und das was man braucht
dann dort kompilieren muss?

Fuer ARM gibt es, Gott sei es gedankt, ja genug kommerzielle 
Alternativen.

von Max H. (nilsp)


Lesenswert?

Schiebe die Funktion in ein eigenes C-File und kompilier es mit 
-ffreestanding. Dann weis GCC, das er für die Datei keine libc 
vorrausetzen darf und lässt diese Optimierung weg.

Ggf. funktioniert auch -fno-builtin-strlen in deinem Fall.

von Rolf M. (rmagnus)


Lesenswert?

Malte _. schrieb:
> Aus
> size_t strlen(const char * text) {
>   size_t len = 0;
>   while(*text) {
>     text++;
>     len++;
>   }
>   return len;
> }
>
> wird mit -Os:strlen:
> b strlen
>
> Benenne ich meine Funktion um, so wird daraus ebenfalls b strlen.
> Der Compiler erkennt also dass meine Implementierung das selbe liefert
> wie strlen und will meine Funktion durch einen Aufruf der Standardlib
> ersetzen.

Rein nach C-Standard ist das korrekt. Das definieren eigener Funktionen, 
deren Name mit str gefolgt von einem Kleinbuchstaben beginnt, führt bei 
einer "hosted"-Impelementation zu undefiniertem Verhalten.

> Wie schalte ich das ab?

Mit -ffreestanding. Das gilt dann aber für alle Standard-Funktionen.

> Bevor jetzt jemand fragt warum ich die Standard strlen Funktion ersetze:
> Meine Implementierung ist zwar nicht unbedingt schneller, aber deutlich
> Programmspeicher sparender als die strlen der newlib (28byte vs
> 220byte).

Wenn du strlen aufrufst, nutzt er dann überhaupt die Implementation der 
newlib? Solche Funktionen sind bei gcc normalerweise bereits im Compiler 
selbst umgesetzt. Das hätte ich gerade bei so einer einfachen Funktion 
wie strlen erwartet.

Motopick schrieb:
> Oder das fuer eine Compilerversion X valider Code, in der
> Compilerversion X+1, sich nur noch als "grosser Haufen von Fehlern"
> praesentiert.

Oft ist der Code nicht valide, sondern der Fehler ist nur nicht 
aufgefallen. Viele Fehler im Code fallen einem erst bei Optimierungen 
auf die Füße. Neue Optimierungen führen daher dazu, dass diese Fehler 
erst in einer neueren Compiler-Version auffallen. Der Fehler liegt dann 
aber trotzdem im Code und nicht im Compiler.

: Bearbeitet durch User
von Malte _. (malte) Benutzerseite


Lesenswert?

Max H. schrieb:
> Schiebe die Funktion in ein eigenes C-File und kompilier es mit
> -ffreestanding.
Danke, damit sieht der Code so aus wie er soll :) Und mit 14 byte dürfte 
es kürzer nicht gehen.

> Ggf. funktioniert auch -fno-builtin-strlen in deinem Fall.
Nein, der erzeugt den selben Code. Ist ja auch zu erwarten. Bei 
nicht-buildin soll er ja die Lib aufrufen, statt gegebenenfalls inline 
Code einzufügen.

Motopick schrieb:
> Ein AVR-GCC verweigerte, ohne weitere Fehlermeldung die Compileroption
> -Os.
Hmm, ja es dürfte einen Grund haben warum Debian für den AVR weiterhin 
gcc version 5 ausliefert.

> Mein Vertrauen in den GCC und die Maintainer ist schon lange gestoert.
In einer älteren gcc version (mit ARM) war mir mal aufgefallen, dass bei 
einer Funktion, die ein float zurück gibt und wo das return vergessen 
wurde der program counter einfach in die nächste Funktion reinläuft, 
weil auch kein Funktionsreturn generiert wird. Das scheint aber in der 
aktuellen Version inzwischen behoben zu sein.

Wirklich gruselig finde ich eher die newlib für ARM. Erst dadurch habe 
ich zu schätzen gelernt wie gut und kompakt die avr-libc geschrieben 
ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Malte _. schrieb:
> wird mit -Os:
1
> strlen:
2
> b strlen

Das ist aber nicht der Code aus dem Beispiel, das du angehangen hast. 
Der wäre
1
> mystrlen:
2
> b strlen

-fno-builtin-strlen wurde schon genannt, funktioniert aber leider nicht:

https://godbolt.org/z/En3j6Gvda

Evtl https://gcc.gnu.org/PR102725

-fno-builtin und -ffreestanding funktionieren zwar, aber die will man 
nicht verwenden, auch nicht auf bare-metal.

Als Work-Around geht zum Beispiel:
1
size_t strlen (const char *text)
2
{
3
  size_t len = 0;
4
5
  while (*text)
6
  {
7
    text++;
8
    len++;
9
    __asm ("");
10
  }
11
12
  return len;
13
}

von Malte _. (malte) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Wenn du strlen aufrufst, nutzt er dann überhaupt die Implementation der
> newlib? Solche Funktionen sind bei gcc normalerweise bereits im Compiler
> selbst umgesetzt. Das hätte ich gerade bei so einer einfachen Funktion
> wie strlen erwartet.
Jup, tut er. Egal welche Optimierung ich wähle, es gibt immer ein bl 
strlen wenn ich strlen aufrufe (deswegen hab ich die ja auch in der Map 
Datei gefunden und durch meine kurze Implementierung ersetzt).
Das macht ja auch Sinn. Bei -Os dürfte Platz gespart werden werden wenn 
strlen mehr als 1x im Programm verwendet wird. Bei -O3 könnte die 
Implementierung für lange strings schneller sein, wenn dann auf einem 
32Bitter immer 4 Byte auf einmal gelesen und verglichen werden 
(erfordert natürlich mehr Code).

von J. S. (jojos)


Lesenswert?

Mit Wrappern kann man die Funktion doch ersetzen?

von Oliver S. (oliverso)


Lesenswert?

Motopick schrieb:
> GCC scheint halt "Bastlersoftware" zu sein.

Das beschriebene Problem ist eins der Distribution, die den gcc mit 
abstrusen Optionen gebaut haben.

Selber mit den passen Optionen compilieren, und alles wird gut. Wenn du 
Linux nutzt, gehört das zum Spiel.

Oliver

von Motopick (motopick)


Lesenswert?

> Selber mit den passen Optionen compilieren, und alles wird gut. Wenn du
> Linux nutzt, gehört das zum Spiel.

Das habe ich vor einiger Zeit tatsaechlich mal wieder probiert.
Von frueher™ kenne ich noch selbst das "Bootstrapping" fuer eine
neue Version. Das ist mir auch immer als recht problemlos in
eigener Erinnerung.

Diesmal sollte es aber der RISCV-GCC fuer den Test eines Softcore 
werden.
Da braucht der Source dann noch droellfzig Patche.
Als Linux haette ein Oracle Linux bereitgestanden.
Einige Stunden spaeter:
Schlussendlich habe ich das "Selberbauen" dann gelassen, und mein
recht kurzes Testprogramm mit dem IAR-Compiler kompiliert. :)
Das dann erwartungsgemaess auch funktionierte.

von Mi N. (msx)


Lesenswert?

Motopick schrieb:
> Schlussendlich habe ich das "Selberbauen" dann gelassen, und mein
> recht kurzes Testprogramm mit dem IAR-Compiler kompiliert. :)
> Das dann erwartungsgemaess auch funktionierte.

Beim 'Versuch' ein IAR-Projekt auf Segger ES (GCC) umzustellen, mache 
ich leider gerade eine ähnliche Erfahrung. Beim RP2040 soll auf das Ende 
einer DMA-Übertragung gewartet werden, was bei IAR problemlos läuft und 
im Fehlerfall einfach zu debuggen wäre.
Eigentlich ganz simpel:
1
void DMA11_transfer_abwarten(void)
2
{
3
  while(DMA->CH11_CTRL_TRIG & DMA_CH11_CTRL_TRIG_BUSY_Msk);
4
}
aber es wird nicht beachtet. Erst eine zusätzliche Warteschleife wirkt 
als notwendige Bremse.
Insofern fand ich die hiesigen Beiträge sehr interessant, daß ich da 
nicht ganz alleine bin.
Irgendwann werde ich weiter 'forschen', trete das Zeug aber zunächst in 
die Tonne. Macht absolut keinen Spaß!

von Vanye R. (vanye_rijan)


Lesenswert?

Oliver S. schrieb:
> Selber mit den passen Optionen compilieren, und alles wird gut. Wenn du
> Linux nutzt, gehört das zum Spiel

Das ist doch wohl eine Selbstverstaendlichkeit. Ich hab alle meins 
Crosscompiler selber uebersetzt. Ich will doch schliesslich auch alle 
meine Cores auf demselben Revisionslevel haben.

Also manchmal denke ich der durchnittliche Linuxuser wird immer bloeder.

Vanye .-)

von Malte _. (malte) Benutzerseite


Lesenswert?

Johann L. schrieb:
> __asm ("");

Danke für den Tipp. Das werde ich mir merken, auch wenn ich denke dass 
ich im jetzigen Fall mit -ffreestanding besser bedient bin.

Mi N. schrieb:
> while(DMA->CH11_CTRL_TRIG & DMA_CH11_CTRL_TRIG_BUSY_Msk);

Bei solchen einfachen Fällen lohnt sich meist ein Blick in den 
generierten Assembler um zu erkennen ob es ein Compiler (falscher 
Assembler) oder Hardware Problem (korrekter Assembler) ist.

Johann L. schrieb:
> Das ist aber nicht der Code aus dem Beispiel, das du angehangen hast.
> Der wäre
Ja sorry. Ich hatte in dem kurzen Beispiel zunächst strlen stehen. Und 
dachte mir das kann einfach nicht sein, dass der gcc an so einer simplen 
Funktion scheitert. Also war mir kurz vor dem Abschicken noch die Idee 
gekommen diese umzubenennen. Das hat mich dann auf die Spur mit dem 
ersetzen des Musters durch strlen gebracht.

Oliver S. schrieb:
> Selber mit den passen Optionen compilieren, und alles wird gut. Wenn du
> Linux nutzt, gehört das zum Spiel.
Das ist bei machen Softwarepaketen aber alles andere als einfach. 
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads -> 
arm-gnu-toolchain-src-snapshot-13.2.rel1.tar.xz -> Entpackt 289065 
Dateien. Vor Jahren hatte ich mal eine Anleitung gefunden wie es dann 
weiter geht. Aber aktuell finde ich nichts. Ist echt gruselig.
Von daher bin ich glücklich dass die Distri Maintainer mir diese Arbeit 
abnehmen. Dass es dabei einen Zielkonflikt gibt "läufts auf einem 
Cortex-M0, M4 oder M7 und möchte der Nutzer kleinen oder schnellen Code" 
ist mir bewusst. Die Newlib in Debian ist definitiv für "so schnell wie 
möglich auf einem M7" übersetzt, wenn man sich das Disassembly anschaut.

: Bearbeitet durch User
von Vanye R. (vanye_rijan)


Lesenswert?

Malte _. schrieb:
> Das ist bei machen Softwarepaketen aber alles andere als einfach

Korrekt. Daher habe ich mich oben auch zu einem Smiley hinreissen 
lassen. In den 90ern war auch fuer Anfaenger vollkommen normal und 
schaffbar Software von Source zu installieren. Mittlerweile hat es aber 
eine Level erreicht wo schon jeden Tag 8h beruflich so was treiben muss. 
Ich mach das jetzt seit 30jahren und komme gelegentlich an Grenzen wo 
ich aufgebe.
Wieso? Weil jeder Programierer sein Waesche nur noch gewaschen bekommt 
in dem er hunderte vom Libaries nutzt die natuerlich in der richtigen 
version vorliegen muessen und Abhaengigkeiten zum Systen habe. Das ganze 
natuerlich Distributionsabhaengig und gerne mit den unterschiedlichsten 
build-tools.
Beim Gcc darf man noch vermuten das Programmier die Spass dran haben den 
neusten Spielkram einer Sprache einzubauen natuerlich den Kram vom 
letzen Jahr nutzen. Da sollte man selber nicht mit einem Compiler vom 
vorletzten Jahr ankommen.

Es wundert mich wie lange das noch beherschbar bleibt. Irgendwann 
bekommen die alten Knacker das nicht mehr gebacken und der Nachwuchs 
schafft es nicht mehr einzusteigen.

Und schuld ist das Unfaehigkeitstheorem der Informatik. Ein Programierer 
ist grundsaetzich nicht in der Lage ein Projekt abzuschliessen und als 
fertig zu erklaeren.
Stellt euch mal vor Ikea kommt an und will am vor einem Jahr gekauften 
Stuhl ein Bein verlaenger und in einer neuen Farbe streiche und eine 
geaenderte sitzhoehe ist auch kein Problem weil ihr euch ja einen neuen 
Tisch kaufen koennt.

Programmierer bemerken ihre Fehle(=Feature) nicht sonder machem aus ihre 
Unfaehigkeit ein Geschaeftsmodel. (software nur noch im Abo)

Vanye

von Harald K. (kirnbichler)


Lesenswert?

Vanye R. schrieb:
> Programmierer bemerken ihre Fehle(=Feature) nicht sonder machem aus ihre
> Unfaehigkeit ein Geschaeftsmodel. (software nur noch im Abo)

Das sind nicht Programmierer, das ist das Management und das Marketing. 
Da der "dernier cri" der Softwareeentwicklung nun mal CI/CD ist, muss 
ständig neue Software produziert werden, immer wieder, ständig neu. 
Egal, ob es tatsächlich nötig ist, man kann sich immer damit rausreden, 
daß irgendeine Abhängigkeit (die x-te Library, die wegen irgendeines 
längst vergessenen Features "gezogen" wird) das so nötig macht.

Und offenbar ist schon wieder vergessen worden, was das blinde Verlassen 
auf irgendwelche Libraries und deren Abhängigkeiten zur Folge haben kann 
- lib4j, erinnert sich noch jemand daran? Ich hab' vor ein paar Jahren 
mal ein so strukturiertes Projekt genauer untersucht (das war irgendwas, 
was SVG renderte), darin steckten gleich drei konkurrierende XML-Parser. 
Mit ihrem jeweiligen Rattenschwanz an Abhängigkeiten, natürlich.

Gäbe man Softwareenwicklern oder Programmierern etwas mehr Zeit, könnten 
sie sich, statt für jeden Furz irgendwas von irgendwem irgendwo 
geschriebenes zu "ziehen", sich intensiver damit beschäftigen, was sie 
eigentlich erreichen wollen, und erkennen, daß a) sie oft den fremden 
Code gar nicht benötigen, weil das Problem auch anders lösbar ist oder 
b) sie den fremden Code auch mit einer halben Stunde Eigenleistung 
ersetzen könnten, nur daß die dann nicht noch drölfzig Abhängigkeiten 
hat.

Aber dazu müssten die Jungs halt nicht nur hippe Architekturkonzepte mit 
bunten Namen kennen, sondern sich mit Grundlagen beschäftigen. Ich habe 
mal einen Java-Programmierer dabei erlebt, wie er in einem 32-Bit-Wert 
nach gesetzten Bits suchte. Nein, er nutzte keinen Schiebeoberator, 
sondern die Funktion pow(). Macht ja nichts, PCs haben ja fett 
Rechenleistung.

von Vanye R. (vanye_rijan)


Lesenswert?

Harald K. schrieb:
> Das sind nicht Programmierer, das ist das Management und das Marketing

Ja ich weiss, hab da natuerlich etwas vereinfacht. .-)

Vanye

von J. S. (jojos)


Lesenswert?

Mi N. schrieb:
> void DMA11_transfer_abwarten(void)
> {
>   while(DMA->CH11_CTRL_TRIG & DMA_CH11_CTRL_TRIG_BUSY_Msk);
> }
> aber es wird nicht beachtet. Erst eine zusätzliche Warteschleife wirkt
> als notwendige Bremse.

Das optimiert der gcc weg weil sich die Bedingung im while Block nicht 
ändert. Die DMA struct oder den Member volatile deklarieren und es wird 
funktionieren. Sowas ist doch kein Fehler.
Über den IAR und die Tools haben hier auch schon einige fürchterlich 
geschimpft, die kochen auch nur mit Wasser. Und auch Keil, kennt der 
mittlerweile aligned_alloc()? Ist ja erst neu im Standard seit C11.
Bei gcc gibt es ein altes issue das die Optimierung für M0 schlecht ist, 
ich weiß nicht ob das schon besser geworden ist. Für M0 hatte der Keil 
mal deutlich kürzeren Code erzeugt, das lag aber auch an der 
schlechteren LTO, die bei gcc mittlerweile auch deutlich besser 
funktioniert.

Und wo braucht die newlib mehr Code für das strlen? Newlib ist 
reentrant, das ist mir mehr Wert als ein paar gesparte Byte. Für MCU mit 
weniger Speicher gibt es ja noch die Newlib nano die für strlen evtl. 
auch weniger braucht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Malte _. schrieb:
> Johann L. schrieb:
>> __asm ("");
>
> Danke für den Tipp. Das werde ich mir merken, auch wenn ich denke dass
> ich im jetzigen Fall mit -ffreestanding besser bedient bin.

Die dafür gedachte Option is -fno-tree-loop-distribute-patterns:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113049#c6

Was allerdings weder aus dem Namen der Option hervorgeht noch aus ihrer 
Dokumentation.

-ffreestanding will man eigentlich nicht verwenden, auch nicht auf 
bare-metal.  Zum Beispiel wird dann strlen("Hallo") nicht mehr zu 5 
optimiert, sondern die Länge des bekannten Strings wird zur Laufzeit 
berechnet.

-fno-builtin-strlen wiederum bewirkt, dass explizte Aufrufe von strlen 
immer zu einem Aufruf von strlen führen.  Ist also auch nicht, was man 
braucht; erklärt aber, warum diese Option nicht wirkt — warum 
-fno-builtin wirkt ist dann wieder schleierhaft...

Aber zurück zum eigentlichen "Problem":

Malte _. schrieb:
> Bevor jetzt jemand fragt warum ich die Standard strlen Funktion ersetze:
> Meine Implementierung ist zwar nicht unbedingt schneller, aber deutlich
> Programmspeicher sparender als die strlen der newlib (28byte vs
> 220byte).

Newlib implementiert eine Speed-optimierte Version von strlen.  Zuerst 
wird bis zu einem bestimmten Alignment byteweise untersucht, danach 
geht's dann in Word-Happen weiter, zumindest für ARM v7:

https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/machine/arm/strlen-armv7.S;h=6aa122c075bbd395c1c1b53925b0a28c3be7294e;hb=HEAD

Für Thumb2 ist der Code dann kürzer:

https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/machine/arm/strlen-thumb2-Os.S;h=4adbc61d2e032ca7593db6b39e938202058583ba;hb=HEAD

Dein Problem ist also, dass -Os keine Multilib-Option ist, und man für 
kleinen Code die Newlib mit speziellen Optionen generieren muss wie -Os 
bzw. -D PREFER_SIZE_OVER_SPEED.

Wenn du die Newlib selbst generiert hast, dann liegt da der Hase im 
Pfeffer.  Bzw. beim Distributor, der wenn es wirklich auf die paar Bytes 
ankommt (tut es das überhaupt?) die Newlib mit entsprechenden Optionen 
generiert haben sollte.

Dann gibt es diese Implementierung, die je nach Gegebenheit die o.g. 
includiert bzw. was eigenes macht:

https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/machine/arm/strlen-stub.c;h=fc2daf16fa30cb755079f2f00f18b1eb643fbcad;hb=HEAD

von Mi N. (msx)


Lesenswert?

J. S. schrieb:
> Das optimiert der gcc weg weil sich die Bedingung im while Block nicht
> ändert. Die DMA struct oder den Member volatile deklarieren und es wird
> funktionieren. Sowas ist doch kein Fehler.

Nicht wegoptimiert, sondern sogar doppelt vorhanden, wobei jeder Aufruf 
noch einmal inline und etwas anders nachgebildet wird. Einmal wird auf 
Bit24 getestet und einandermal 7 x nach links geschoben und auf negativ 
getestet.
Egal, ich bekomme das in den Griff.

von Oliver S. (oliverso)


Lesenswert?

J. S. schrieb:
> Das optimiert der gcc weg weil sich die Bedingung im while Block nicht
> ändert. Die DMA struct oder den Member volatile deklarieren und es wird
> funktionieren. Sowas ist doch kein Fehler.

Das DMA-Struct stammt aus den vom Hersteller für den Prozessor 
bereitgestellten Headern. Wenn das nicht volatile definiert sein sollte, 
wäre das ein signifikanter Fehler da drin. Das sollte aber nicht der 
Fall sein.

Oliver

von Malte _. (malte) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Die dafür gedachte Option is -fno-tree-loop-distribute-patterns:
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113049#c6
>
> Was allerdings weder aus dem Namen der Option hervorgeht noch aus ihrer
> Dokumentation.
Vielen dank, das hätte ich wohl nicht gefunden. :)
Da war ja ein Bug Reporter genau 1 Tag schneller als ich. Schön die 
Hintergründe zu lesen. Ich hab jetzt wie empfohlen 
-fno-tree-loop-distribute-patterns als Lösung genommen:
https://github.com/Solartraveler/UniversalboxArm/commit/dba37e42acd4dd493cb93c3016aef0d5abeb90f1

Johann L. schrieb:
> Für Thumb2 ist der Code dann kürzer:
>
> 
https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/machine/arm/strlen-thumb2-Os.S;h=4adbc61d2e032ca7593db6b39e938202058583ba;hb=HEAD

Ok, dass es auch eine größenoptimierte Version gibt, wusste ich nicht. 
Wie oben schon geschrieben verlasse ich mich auf die vorkompilierte 
Version.

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.