Forum: Compiler & IDEs WinAVR rettet bei Funktionsaufruf nicht alle Register !?


von Uwe Nagel (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

habe stundenlang nach einem Fehler in meinem Programm gesucht und glaube 
ihn jetzt im Compiler gefunden zu haben.
Ich habe eine Funktion definiert:
  void sun( int year, int month, int day, double longitude,   double 
latitude, int rise, int localOffset, zeit_t* zeit );

rufe ich sie zweimal hintereinander auf, nur mit 0 bzw 1 für den 
Parameter rise, zeigt sich, dass der zweite Aufruf nicht das gewünschte 
Ergebnis bringt.
Im Listing sehe ich, dass das Unterprogramm die Register r2-r17 und 
r28-r29 auf den Stack rettet.
Die Parameterübergabe erfolgt aber auch über r18 und r19.
Die werden nicht gerettet, der Compiler scheint das aber zu erwarten, 
denn beim zweiten Aufruf glaubt er, das die Parameter noch alle in ihren 
Registern stehen, nur die geänderten Register und r20-r25 (nicht 
gerettet) werden neu gesetzt.
R18 und r19 werden im Unterprogramm verändert!
Deshalb stimmt der Parameter Longitude beim zweiten Aufruf nicht!

Habe mir erstmal damit geholfen, nicht mehr so viele Parameter zu 
übergeben...

Kennt jemand das Problem?

Im Anhang mein stark gekürztes Programm (tut nix sinnvolles), das 
trotzdem den Fehler zeigt.

Bevor jemand fragt: es soll mal eine Uhr werden, die Sonnenauf- und 
untergangszeiten anzeigt. Nach Umstieg auf einen megaAVR wird wohl auch 
noch der Mond drankommen.

schon mal danke für die zahlreichen Antworten
Uwe
http://www.uwe-nagel.de.vu

von R2D2 (Gast)


Lesenswert?

Ich glaub da war vor kurzem in der GCC-Mailinglist der selbe Bugreport. 
Ich weiß leider nicht ob das schon gefixt ist. Versuch mal die 
aktuelleste avr-gcc version.

von Uwe Nagel (Gast)


Lesenswert?

hab mir extra die neueste runtergeladen, macht den Fehler genauso...

von Joerg Wunsch (Gast)


Lesenswert?

Nö, r18 + r19 gehören zu den `clobber' Registern, die muß eine
gerufene Funktion nicht retten.  Der Bugreport in der avr-gcc
Liste bezog sich darauf, daß eine 32-Bit-Zahl die Register
r16..r19 belegt hat.  Der Compiler hat daraus fälschlicherweise
abgeleitet (r18/r19-mäßig), daß diese Register nicht gerettet
werden müssen, und hat dabei mit dem Funktionsaufruf r16/r17
zerstört.

Nö, habe mir nochmal den generierten Assemblercode angesehen,
das könnte in der Tat dieses Problem sein...

von Peter D. (peda)


Lesenswert?

Ich habe bisher noch nie einen Funktionsaufruf mit einer derart hohen 
Zahl von Argumenten gesehen. Warscheinlich die Compilerbauer auch nicht. 
Aber dann sollte der Compiler wenigstens eine Fehlermeldung ausgeben.

Der üblichere und Ressourcen schonendere Weg ist die Übergabe als 
Pointer auf ein Array oder eine Struktur.
Sowas lohnt sich schon oft bei mehr als 3 Argumenten.

Außerdem würde ich einen 8-Bitter nie unnötiger Weise mit "int" quälen, 
z.B. bei Monat (1..12).

Auch zur besseren Verständlichkeit nehme ich für Variablen, wo negative 
Werte unsinnig sind, immer "unsigned", z.B. bei Monat (+1..+12). Sowas 
schont auch die Ressourcen.


Auf der Atmel-Seite gibt es eine sehr informative Applikationsnote mit 
C-Programmiertips. Sollte sich jeder MC-Programmierer mal reinziehen.


Peter

von Joerg Wunsch (Gast)


Lesenswert?

Warum sollte die Übergabe als struct oder array ressourcenschonender
sein?  Die einzelnen Parameter können in Registern übergeben
werden, so daß erstmal keine Speicherzugriffe nötig sind.  Gut,
das wird durch die in den Stack zu rettenden Register wieder
teilweise aufgehoben, aber ich würde ohne eingehende Analyse
nicht die eine oder andere Variante per se als ressourcenschonender
bezeichnen.

Die Compilerbauer haben durchaus auch schon so viele Argumente
gesehen, das Problem entsteht nur dann, wenn ein 32-bit
Argument sich über die Grenze r17/r18 erstreckt.

von Joerg Wunsch (Gast)


Lesenswert?

Ich sehe übrigens in der aktuellen Compilerversion (GCC aus dem
CVS, gcc-3_3-branch) von gestern kein Problem mehr.  Der Aufrufer
(main()) lädt jedesmal r16...r19 komplett, der Aufgerufene (sun())
sichert von r2 bis r17 und r28/r29 komplett.

von Peter D. (peda)


Lesenswert?

@Joerg,

"Warum sollte die Übergabe als struct oder array ressourcenschonender 
sein?"

Der Aufrufer muß sie ja erst vom RAM in Register packen, d.h. Kopien 
anlegen. Der Aufgerufene will aber mit den Registern auch arbeiten, wird 
also erstmal den Großteil wieder im RAM sichern.

Bedeutet also doppelt RAM, doppelt Code.

Der AVR kann doch gut mit Zeigern+Displacement umgehen, d.h er holt sich 
die Variablen bequem aus dem RAM, aber erst genau dann, wenn er sie auch 
benötigt.


Ist aber meine rein persönliche Erfahrung, daß C-Compiler sehr gut auf 
die Arbeit mit Zeigern hin optimiert sind. D.h. ab >=4 Argumenten ergibt 
sich mit Zeigern oftmals ein kleinerer und schnellerer Code.


Peter

von Peter D. (peda)


Lesenswert?

Ich persönlich mag es gern, wenn man zusammengehörende Variablen (z.B. 
Tag, Monat, Jahr) dann auch in Strukturen zusammenfaßt.

Das Programm wird dadurch besser lesbar.


Peter

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.