Hallo, gibt es ein Tool, dass durch statische Codeanalyse die maximale Stacktiefe für AVR-Controller berechnen kann? Gruß Matthias
Matthias Kölling wrote: > gibt es ein Tool, dass durch statische Codeanalyse die maximale > Stacktiefe für AVR-Controller berechnen kann? Ja -> Beitrag "StackViewer (RAM Rechner) für WinAVR"
Hi Benedikt K. kann man mit Deinem Tool wirklich zu jedem Zeitpunkt die Stack-Tiefe berechnen? Halte ich für ein Gerücht! Dieses ist warscheinlich genau so unmöglich wie die exakte Laufzeit einens Programmes zu berechnen. (Interrupts, ...) mfg Jens
Ok, das ist ja wirlich ein süßes Tool. Aber die Probleme hören damit nicht auf. Wieso meldet es 9 errors, 0 Warnings. Leider hat Benedikt nichts dazu in seiner Anleitung geschrieben. Die "total RAM usage" ist aber laut Tool kleiner als der vorhandene RAM, trotzdem macht mein Teil resets... Grübel, Grübel... Gruß Matthias
Jens wrote: > kann man mit Deinem Tool wirklich zu jedem Zeitpunkt > die Stack-Tiefe berechnen? Ja, bis auf die Einschränkungen die dabei stehen. > Halte ich für ein Gerücht! Dann probiers aus. > Dieses ist warscheinlich genau so unmöglich wie die exakte > Laufzeit einens Programmes zu berechnen. (Interrupts, ...) Es ist eine worst case Betrachtung, die solange funktioniert, bis irgendwelche Dinge auftreten die erst zur Laufzeit entschieden werden, wie rekursive Funktionen, IJMPs usw. Klar, man kann Konstruktionen bauen, bei denen das Programm falsche Werte liefern wird, aber für praxisübliche Programme sollte der Wert doch relativ gut hinkommen. Matthias Kölling wrote: > das ist ja wirlich ein süßes Tool. > Aber die Probleme hören damit nicht auf. Wieso meldet es 9 errors, 0 > Warnings. Leider hat Benedikt nichts dazu in seiner Anleitung > geschrieben. Ein Error heißt, dass irgendwas nicht so läuft wie es soll (ich habe aus Gründen der Einfachheit viele Annahmen getroffen). Könntest du mal die lss und die elf Datei posten? Dann schau ich mir das mal an und versuche die Fehler zu beheben. Das Programm ist alles andere als ausgereift, aber ich musste einen Kompromiss aus Zeit die ich dafür investieren wollte und Gründlichkeit machen.
@ Matthias Kölling lass es! schreib Dir eine Routine, die Du in den verdächtigen Programmteilen aufrufst, die über irgendwas (LCD, RS232 ...) den Stackpointer ausgibt. Oder die Routine merkt sich den Tiefsten Stackpointer im RAM, den Du irgend wie abfragst. Wenn Du den Stack-Verbrauch hast, rechne noch ein paar Prozent dazu, dann bist Du auf der sicheren Seite.
Hallo Benedikt, die Hilfe nehme ich doch gerne an! Aus Deinen Sourcen und dem Ausgabefile habe ich inzwischen rausbekommen, dass der Fehler "unknown function" mehrmals auftritt. Gruß Matthias
Hi Benedikt K. >> Dieses ist warscheinlich genau so unmöglich wie die exakte >> Laufzeit einens Programmes zu berechnen. (Interrupts, ...) >Es ist eine worst case Betrachtung, die solange funktioniert, bis >irgendwelche Dinge auftreten die erst zur Laufzeit entschieden werden, >wie rekursive Funktionen, IJMPs usw. >Klar, man kann Konstruktionen bauen, bei denen das Programm falsche >Werte liefern wird, aber für praxisübliche Programme sollte der Wert >doch relativ gut hinkommen. .. und die "praxisübliche Programme" entstehen bei mir bei der Entwicklung in Serie. :)
Den Ursache für die Fehler habe ich gefunden, ich muss nur noch rausfinden, was der Compiler damit bezweckt: 90c: 0f 93 push r16 90e: 1f 93 push r17 910: df 93 push r29 912: cf 93 push r28 914: 00 d0 rcall .+0 916: 00 d0 rcall .+0 Kann mir jemand verraten, welchen Sinn "rcall .+0" hat?
Benedikt K. wrote:
> Kann mir jemand verraten, welchen Sinn "rcall .+0" hat?
Platz auf dem Stack schaffen für lokale Variablen?
in ASM gibs das nicht
> rcall .+0
.+0 wäre ein Label das in ASM nicht zulässig ist!
mfg Jens
Legend: r any register d `ldi' register (r16-r31) v `movw' even register (r0, r2, ..., r28, r30) a `fmul' register (r16-r23) w `adiw' register (r24,r26,r28,r30) e pointer registers (X,Y,Z) b base pointer register and displacement ([YZ]+disp) z Z pointer register (for [e]lpm Rd,Z[+]) M immediate value from 0 to 255 n immediate value from 0 to 255 ( n = ~M ). Relocation impossible s immediate value from 0 to 7 P Port address value from 0 to 63. (in, out) p Port address value from 0 to 31. (cbi, sbi, sbic, sbis) K immediate value from 0 to 63 (used in `adiw', `sbiw') i immediate value l signed pc relative offset from -64 to 63 L signed pc relative offset from -2048 to 2047 h absolute code address (call, jmp) S immediate value from 0 to 7 (S = s << 4) ? use this opcode entry if no parameters, else use next opcode entry 1001010010001000 clc 1001010011011000 clh 1001010011111000 cli 1001010010101000 cln 1001010011001000 cls 1001010011101000 clt 1001010010111000 clv 1001010010011000 clz 1001010000001000 sec 1001010001011000 seh 1001010001111000 sei 1001010000101000 sen 1001010001001000 ses 1001010001101000 set 1001010000111000 sev 1001010000011000 sez 100101001SSS1000 bclr S 100101000SSS1000 bset S 1001010100001001 icall 1001010000001001 ijmp 1001010111001000 lpm ? 1001000ddddd010+ lpm r,z 1001010111011000 elpm ? 1001000ddddd011+ elpm r,z 0000000000000000 nop 1001010100001000 ret 1001010100011000 reti 1001010110001000 sleep 1001010110011000 break 1001010110101000 wdr 1001010111101000 spm 000111rdddddrrrr adc r,r 000011rdddddrrrr add r,r 001000rdddddrrrr and r,r 000101rdddddrrrr cp r,r 000001rdddddrrrr cpc r,r 000100rdddddrrrr cpse r,r 001001rdddddrrrr eor r,r 001011rdddddrrrr mov r,r 100111rdddddrrrr mul r,r 001010rdddddrrrr or r,r 000010rdddddrrrr sbc r,r 000110rdddddrrrr sub r,r 001001rdddddrrrr clr r 000011rdddddrrrr lsl r 000111rdddddrrrr rol r 001000rdddddrrrr tst r 0111KKKKddddKKKK andi d,M 0111KKKKddddKKKK cbr d,n 1110KKKKddddKKKK ldi d,M 11101111dddd1111 ser d 0110KKKKddddKKKK ori d,M 0110KKKKddddKKKK sbr d,M 0011KKKKddddKKKK cpi d,M 0100KKKKddddKKKK sbci d,M 0101KKKKddddKKKK subi d,M 1111110rrrrr0sss sbrc r,s 1111111rrrrr0sss sbrs r,s 1111100ddddd0sss bld r,s 1111101ddddd0sss bst r,s 10110PPdddddPPPP in r,P 10111PPrrrrrPPPP out P,r 10010110KKddKKKK adiw w,K 10010111KKddKKKK sbiw w,K 10011000pppppsss cbi p,s 10011010pppppsss sbi p,s 10011001pppppsss sbic p,s 10011011pppppsss sbis p,s 111101lllllll000 brcc l 111100lllllll000 brcs l 111100lllllll001 breq l 111101lllllll100 brge l 111101lllllll101 brhc l 111100lllllll101 brhs l 111101lllllll111 brid l 111100lllllll111 brie l 111100lllllll000 brlo l 111100lllllll100 brlt l 111100lllllll010 brmi l 111101lllllll001 brne l 111101lllllll010 brpl l 111101lllllll000 brsh l 111101lllllll110 brtc l 111100lllllll110 brts l 111101lllllll011 brvc l 111100lllllll011 brvs l 111101lllllllsss brbc s,l 111100lllllllsss brbs s,l 1101LLLLLLLLLLLL rcall L 1100LLLLLLLLLLLL rjmp L 1001010hhhhh111h call h 1001010hhhhh110h jmp h 1001010rrrrr0101 asr r 1001010rrrrr0000 com r 1001010rrrrr1010 dec r 1001010rrrrr0011 inc r 1001010rrrrr0110 lsr r 1001010rrrrr0001 neg r 1001000rrrrr1111 pop r 1001001rrrrr1111 push r 1001010rrrrr0111 ror r 1001010rrrrr0010 swap r 00000001ddddrrrr movw v,v 00000010ddddrrrr muls d,d 000000110ddd0rrr mulsu a,a 000000110ddd1rrr fmul a,a 000000111ddd0rrr fmuls a,a 000000111ddd1rrr fmulsu a,a 1001001ddddd0000 sts i,r 1001000ddddd0000 lds r,i 10o0oo0dddddbooo ldd r,b 100!000dddddee-+ ld r,e 10o0oo1rrrrrbooo std b,r 100!001rrrrree-+ st e,r 1001010100011001 eicall 1001010000011001 eijmp es existiert kein Op-Code bei AVR mit 0x00d0 mfg Jens
Stefan Ernst wrote: > Platz auf dem Stack schaffen für lokale Variablen? Stimmt. Wenn ich mir das so überlege, macht es sogar Sinn: 1 Befehl der 3 Takte braucht und 2 Bytes auf dem Stack schafft. 2x push würde dasselbe bewirken, wäre aber doppelt so groß und würde 1 Takt länger brauchen. Solche Zweckentfremdungen sind natürlich auch ein Hindernis für die Stackanalyse. Ich habe mal eine neue Version angehängt. Damit läuft das Programm mit 0 Fehlern und Warnungen durch. Ich vermute mal du verwendest einen mega128 oder irgendwas in der Richtung mit 4kByte SRAM. Falls ja, dann kann man davon ausgehen, dass das Problem nicht am Stack liegt wenn der AVR neustartet. Vielleicht ein Pointer der durcheinander kommt, oder ein ausgelöster Interrupt ohne passenden Interrupthandler? Jens wrote: > es existiert kein Op-Code bei AVR mit 0x00d0 Vertausch mal die Bytes, dann wird 0xd000 draus: 1101000000000000 Und das ist das hier: 1101LLLLLLLLLLLL rcall L -> rcall 0
@ Jens: Denk dran: Little Endian. Speicher 0x000d -> Opcode 1101000000000000 -> rcall mit Offset 0 Und dass der von dir verwendete Assembler ein .+0 nicht als Label akzeptiert, spielt absolut keine Rolle. Null ist als Offset trotzdem erlaubt.
@ Benedikt K.
>Vertausch mal die Bytes, dann wird 0xd000 draus: 1101000000000000
ich Dummkopf hab das über sehen.
der Macht wirklich ein Warm-Start (Reset) :)
Jens wrote:
> der Macht wirklich ein Warm-Start (Reset) :)
Ernst gemeint oder Scherz?
Da ich den möglichen Scherz irgendwie nicht sehe, befürchte ich fast
Ersteres. Die Null ist ein relativer Offset, keine absolute Adresse.
>der Macht wirklich ein Warm-Start (Reset) :)
quatsch der ruft sich selst auf auf eigener Adresse auf
und verursacht dadurch eine Stack-Überlauf!
Hi, das ist ja interessant! Heißt das, dass mir der Compiler einen reset einbaut??? Dann müßte er doch aber immer kommen, wenn die Funktion aufgerufen wird. Dieses Verhalten sehe ich aber nicht. Statt dessen läuft das Programm eine Weile normal. Ich compiliere jetzt noch mal die Version, wo der reset nicht aufgetreten ist und schau mir das .lss File noch mal an. Danke erst mal! Gruß Matthias
edit: quatsch der ruft sich selbst, auf eigener Adresse auf und verursacht dadurch einen Stack-Überlauf! sorry Jens
Matthias Kölling wrote: > das ist ja interessant! Heißt das, dass mir der Compiler einen reset > einbaut??? Hör nicht auf Jens, der schreibt hier nur Blödsinn. Was der Compiler da macht, ist absolut korrekt.
Hi >quatsch der ruft sich selbst, auf eigener Adresse auf >und verursacht dadurch einen Stack-Überlauf! Bevor du solche Enten in die Welt setzt, solltest dich mal informieren, von welcher Adresse aus der Offset berechnet wird. MfG Spess
Jens wrote: > label: > rcall Label Das ist aber kein rcall mit Offset 0, sondern mit Offset -2 oder -1, je nachdem, ob du es lieber byte- oder wortweise betrachtest.
Ok rcall 0 rcall 0 wie oft kann mann rcall 0 nacheinander aufrufen bis der RAM voll ist (ohne ret)? mfg Jens
> wie oft kann mann rcall 0 nacheinander aufrufen bis der RAM > voll ist (ohne ret)? Herrgott, am Ende der Funktion wird der Stackpointer dann wieder korrigiert, entweder mit Pops oder mit einer Addition auf den Stackpointer.
Stefan Ernst wrote: > Herrgott, am Ende der Funktion wird der Stackpointer dann wieder > korrigiert Genau: Anfang: 90a: ff 92 push r15 90c: 0f 93 push r16 90e: 1f 93 push r17 910: df 93 push r29 912: cf 93 push r28 914: 00 d0 rcall .+0 916: 00 d0 rcall .+0 Ende: cba: 0f 90 pop r0 cbc: 0f 90 pop r0 cbe: 0f 90 pop r0 cc0: 0f 90 pop r0 cc2: cf 91 pop r28 cc4: df 91 pop r29 cc6: 1f 91 pop r17 cc8: 0f 91 pop r16 cca: ff 90 pop r15
@ Stefan Ernst >Herrgott, am Ende der Funktion wird der Stackpointer dann wieder >korrigiert, entweder mit Pops oder mit einer Addition auf den >Stackpointer. und wo steht das > 90c: 0f 93 push r16 > 90e: 1f 93 push r17 > 910: df 93 push r29 > 912: cf 93 push r28 > 914: 00 d0 rcall .+0 > 916: 00 d0 rcall .+0 gerade die Zeilen: 914: 00 d0 rcall .+0 916: 00 d0 rcall .+0 .. gefallen mir "Nop"s mit 3-Takt-Zyklen + 3 fürs "Popen" wenns vorhanden
Jens wrote: > .. gefallen mir "Nop"s mit 3-Takt-Zyklen + 3 fürs "Popen" wenns > vorhanden Hast du irgendwie Langeweile? Der Zweck ist doch längst geklärt. Hier wird auf sparsame Weise ein Stackframe erzeugt.
Hi, um die Wogen etwas zu glätten: Das Listfile ist an dieser Stelle bei beiden Varianten(funktionierend, nichtfunktionierend) identisch. Was ich machen will ist ein scan einer Verzeichnisstruktur auf einer SD-card. Ich hatte diese Woche dazu schon einen Thread. Ich habe mir wirklich einen abgebrochen, den Algorithmus hinzubekommen. Wenn ich jetzt die Ausgabe auf der UART mache erfolgt nach dem scan genau 1 Reset. Nach dem zweiten Mal ist Ruhe?! Wenn ich das Ergebnis in eine Datei schreibe, wird der scan irgendwo durch einen reset unterbrochen und das Ganze wiederholt sich. Es scheint wohl etwas beim Schreiben in die Datei schiefzugehen. Das kann ich ja eruieren. Komisch ist der erstere Fall. Jetzt habe ich auch festgestellt, dass manchmal auch ein reset nach der Willkommensbotschaft, die als erste in der main verschickt wird, ein reset auftritt. Und da sollte noch kein Stack übergelaufen sein?! Danke soweit! Gruß Matthias
Nö >Autor: Matthias Kölling (Gast) >Datum: 09.01.2009 17:27 >Hallo, >gibt es ein Tool, dass durch statische Codeanalyse die maximale >Stacktiefe für AVR-Controller berechnen kann? >Gruß Matthias das war der Ausgang. ich wollte nur helfen. Jens
Matthias Kölling wrote: > Jetzt habe ich auch festgestellt, dass manchmal auch ein reset nach der > Willkommensbotschaft, die als erste in der main verschickt wird, ein > reset auftritt. Und da sollte noch kein Stack übergelaufen sein?! Eher unwarscheinlich, außer du hast mehr globale Variablen als RAM vohanden ist. Bleiben noch die üblichen Ursachen: - Ein Interrupt ohne Handler - Pointer überschreiben den Stack - Instabile Betriebsspannung/Takt (CKOPT bei alten AVRs bei >8MHz)
>Wenn ich jetzt die Ausgabe auf der UART mache erfolgt nach dem scan >genau 1 Reset. ist das so gewollt? wenn nicht, untersuche mal die Ursachen bevor Du weiter machst! Jens
Hallo, das Problem scheint sich auf meine fprintf zu konzentrieren (im Anhang). Es hat aber scheinbar nichts mit dem Schreiben in eine Datei zu tun, denn das Problem tritt auch auf, wenn ich innerhalb der fprintf die Schreibfunktion auskommentiere. Erst wenn ich den ganzen Block unterhalb der for-Schleife auskommentiere sind die resets weg. Ich lasse mir in dieser Funktion die maximale Stacktiefe ausgeben und die liegt bei 0x10AC. Das dürfte weit genug weg sein von den statischen Variablen, die 2831 Bytes umfassen. Der RAM hat 4096 Bytes (644P). Es ist auch insofern verblüffend, dass meine printf-Funktion genau so aussieht, nur dass die Ausgabefunktion eine andere ist. Diese Funktion macht aber keinen Ärger. Hat jemand eine Idee, was es noch sein könnte? Danke und Gruß Matthias
Matthias Kölling wrote: > Erst wenn ich den ganzen Block unterhalb > der for-Schleife auskommentiere sind die resets weg. Dann dürfte es klar sein: va_end (ap); fehlt am Ende der Funktion, was dazu führen könnte, dass der Stack durcheinander kommt.
va_end habe ich schon immer für unnötig gehalten :-) Mich stört viel mehr, dass das Durchsuchen einer Verzeichnisstruktur sehr gerne rekursiv implementiert wird. Insofern sehr ich hier einen Verdächtigen. @Matthias: Hast Du rekursive Aufrufe im Programm?
Hi, sorry, ich meinte natürlich, dass die while-Schleife, die den String scannt und bei Erreichen des Endes va_end() aufruft als einziges in for-Schleife veblieben ist. Aber ich hatte auch schon die for-Schleife rausgeschmissen, so dass va_end() nicht aufgerufen wurde und da gabs komischerweise auch keine resets mehr?! Rätsel über Rätsel... Gruß Matthias
Eddy Current wrote: > @Matthias: Hast Du rekursive Aufrufe im Programm? Dürfte er nicht drin haben, das würde mein StackViewer anzeigen. Matthias Kölling wrote: > Aber ich hatte auch schon die for-Schleife > rausgeschmissen, so dass va_end() nicht aufgerufen wurde und da gabs > komischerweise auch keine resets mehr?! Pack mal va_end ans Ende der Funktion und schau mal obs dann geht. Ich muss mal nach offiziellen Angaben suchen, auf die Schnelle habe ich nur das hier gefunden (http://docs.codegear.com/docs/radstudio/radstudio2007/RS2007_helpupdates/HUpdate3/DE/html/devwin32/va_arg_xml.html): va_end: Dieses Makro hilft der aufrufenden Funktion, normal zurückzukehren. va_end kann ap so ändern, dass ap erst wieder verwendet werden kann, wenn va_start erneut aufgerufen wird. va_end sollte aufgerufen werden, nachdem va_arg alle Argumente gelesen hat; wird dies unterlassen, könnte ein seltsames, nicht definiertes Verhalten Ihres Programms die Folge sein. Edit: Auch K&R sagt, dass va_end zwingend notwendig ist: Finally, va_end does whatever cleanup is necessary. It must be called before the program returns.
@Eddy Ich habe es vermieden,rekursive Aufrufe zu programmieren, da das sehr schnell den Stack sprengt, vor allem wenn man nicht weiß wie viele verschachtelte Aufrufe es letztendlich sein werden. Ich hänge mal das File mit dem scan an. Vielleicht seht Ihr noch etwas, was ich bisher übersehen habe. Gruß Matthias
Hi, Asche auf mein Haupt! Es ist das Fwrite(). Einen Aufruf hatte ich vergessen auszukommentieren. Sobald es weg ist, funktioniert es. Aaußerhalb des scans funktioniert es aber und es schreibt auch etwas sinvolles in das File. Guß Matthias
>Asche auf mein Haupt! Es ist das Fwrite(). Einen Aufruf hatte ich >vergessen auszukommentieren. Sobald es weg ist, funktioniert es. >Aaußerhalb des scans funktioniert es aber und es schreibt auch etwas >sinvolles in das File. Das wird wohl daran liegen das du die fileid der offenen Datei auch zum scannen des Verzeichnisses benutzt. Autsch! Ich denke du würdest mit den Funktionen Findfirst(), Findnext() und Chdir() auch zum Ziel kommen. Dann musst du das DOS nicht so vergewaltigen.
Hallo Holger, ich benutze nur eine fileid, und zwar die für das zu schreibende file. Ich dachte das Lesen von Verzeichnissen geht über dirbuf (by=ReadSector(sector,dirbuf);), oder habe ich da was falsch verstanden? Gruß Matthias
>Ich dachte das Lesen von Verzeichnissen geht über dirbuf >(by=ReadSector(sector,dirbuf);), oder habe ich da was falsch verstanden? Ja, das stimmt. Nach näherem hinsehen benutzt du fileid auch nur für die Datei. Warum Fwrite() da jetzt scheinbar abschmiert ist mir ein Rätsel.
Holger noch da? Ich konnte die Ursache bis zu MMCWriteSector() zurückverfolgen. Eine Änderung der Geschwindigkeit brachte keine Besserung. Die eingeschalteten Debuginfos haben bis zum Reset keinen Fehler angezeigt. Gruß Matthias
Hast du vielleicht den Watchdog an? Falls nein, poste doch mal die entsprechende Datei mit der Funktion drin.
Hi, der Watchdog kann nicht an sein. Ich gehe nach dem scan in eine Endlosschleife. Nach erfolgreichem scan, also ohne fprintf(), bleibt er da auch ganz brav. Gruß Matthias
>Holger noch da? Hier, wo die Hand leuchtet ;) >Ich konnte die Ursache bis zu MMCWriteSector() zurückverfolgen. Eine >Änderung der Geschwindigkeit brachte keine Besserung. Die >eingeschalteten Debuginfos haben bis zum Reset keinen Fehler angezeigt. Die Routine bleibt bei Problemen evtl. hängen, aber einen Reset löst die bestimmt nicht aus. Hat sie bei mir noch nie getan und so etwas wurde mir auch noch nicht berichtet. Da muss was anderes faul sein. Wenn du magst poste doch mal die Sources zum Projekt. Oder schick mir ne Mail. Adresse kennst du.
Hallo Holger, ich schick Dir ne mail mit dem Projekt. Danke und Gruß Matthias
Hallo, ich möchte gerne diesen Post abschließen, da ich meinen Fehler nun gefunden habe. Dieser hat absolut nichts mit meiner Anfangsvermutung (Stackoverflow) zu tun. Nachdem Holger mein Projekt nun getest hat und bei ihm keine Resets festzustellen waren, mußte etwas an meiner Hardware foul sein. Nachdem ich am Resetpin mit einem Schätzoszi so etwas ähnliches wie Pulse gesehen habe, die AVRs interne Resets aber nicht nach außen spiegeln kam nur die umliegende Hardware in Frage. Der Übeltäter war schnell ausgemacht. Es war der Spannungsregler. Der kann scheinbar nicht genug Strom liefern, von dem guten Saft wird beim Schreiben auf die SD-Karte wohl etwas mehr gebraucht, die Spannung bricht ein und der Resetbaustein löst einen Reset aus. Nachdem ich 3,3V direkt hinter dem Spannungsregler eingespeist hatte, war alles gut. Peinlich wenn man für dieses Modul 89€ + 8€ Porto aus der Schweiz bezahlt hat. Den Spannungsregler kann ich nicht identifizieren. Der Schaltplan hat eine ältere Versionsnummer als die Platine. Im Schaltplan ist er mit XC6202M322 angegeben. Es ist ein SOT23. Auf dem Gehäuse hat er aber die Markierung 252A. Danke allen für die fleißige Mitarbeit! Gruß Matthias
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.