mikrocontroller.net

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


Autor: Uwe Nagel (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: R2D2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Uwe Nagel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab mir extra die neueste runtergeladen, macht den Fehler genauso...

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.