Forum: Compiler & IDEs mega 32 compilerfehler


von M. Gerlach (Gast)


Lesenswert?

hallo leute

ich hatte im laufe der woche schon eine umfrage gestartet wegen eines
vermuteten compilerfehlers. hier nochmal die eckdaten:

avrgcc3.3, pn2, avrstudio4.11 und jtag-ice
compilereinstellungen: richtiger controller, optimierung s
programmiert wird in c.

folgendes detail:

123:        dac_set_value(URDM_1,-1.5);    // AP für MOSFET UGS=-3V
+00000FC2:   E040        LDI     R20,0x00         Load immediate
+00000FC3:   E050        LDI     R21,0x00         Load immediate
+00000FC4:   EC60        LDI     R22,0xC0         Load immediate
+00000FC5:   EB7F        LDI     R23,0xBF         Load immediate
+00000FC6:   E081        LDI     R24,0x01         Load immediate
123:        dac_set_value(URDM_1,-1.5);    // AP für MOSFET UGS=-3V
+00000FC7:   940E0000    CALL    0x00000000       Call subroutine
127:          dac_set_value(US_1,1.5);    // Startpunkte setzen
+00000FC9:   E040        LDI     R20,0x00         Load immediate
---- No Source
------------------------------------------------------------------------ 
------------
+00000FCA:   E050        LDI     R21,0x00         Load immediate
+00000FCB:   EC60        LDI     R22,0xC0         Load immediate
+00000FCC:   E37F        LDI     R23,0x3F         Load immediate
+00000FCD:   E080        LDI     R24,0x00         Load immediate
+00000FCE:   CFF8        RJMP    PC-0x0007        Relative jump

hinter diesem asm-code verbergen sich folgende zeilen im pn

  dac_set_value(URDM_1,-1.5);

  for(;;)
  {
    dac_set_value(US_1,1.5);

  }
effekt1:

der pc wird vom compiler aus der schleife herausgeschickt
in die zeile vor der schleife!

+00000FCE:   CFF8        RJMP    PC-0x0007        Relative jump

wer hat infos woran das liegen kann?

m. gerlach

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gib mal bitte ein Stückchen minimalen C-Code, der das
reproduziert, statt eines Schnipsels aus dem Disassembler
von AVR Studio (der noch dazu bekanntermaßen mit negativen
Offsets Probleme hat).

von M. Gerlach (Gast)


Lesenswert?

der c-code sieht so aus


 dac_set_value(URDM_1,-1.5);

  for(;;)
  {
    dac_set_value(US_1,1.5);

  }
die funktion ist jedoch etwas umfangreicher

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, ich wollte etwas compilierfähiges haben, damit ich mir
den Compiler-Output mal angucken kann.

Aber eigentlich hat sich das schon erledigt, mir ist auf dem
Heimweg beim Radeln eingefallen, dass der Compiler eben einfach
nur genial compiliert hat.

Der Code ist komplett korrekt.  Der Compiler hat nur festgestellt,
dass er die beiden Funktionsaufrufe in einen vereinigen kann.
Das ist ein typisches Beispiel, an dem man sieht, dass es eben
einfach nicht immer eine 1:1-Zuordnung vom Objektcode zurück zum
C-Code geben kann: der Funktionsaufruf auf Adresse 0xFC7 gehört
sowohl zu Zeile 123 als auch Zeile 127 im Quelltext.

von A.K. (Gast)


Lesenswert?

Wo ist nun dein Problem? Der RJMP spring nach 0FC7 und genau das soll er
doch auch. Nur ist der Compiler ein bischen schlauer als Du angenommen
hast, denn er verwendet den selben CALL-Befehl gleich für beide
Funktionsaufrufe. Nur eben mit verschiedenen Parametern. Genau wie er
soll.

von Marco G. (macro)


Lesenswert?

@Jörg


Ja und was soll ich jetzt tun damit dieser Fehler nicht mehr auftritt?
Denn es ist doch wohl ein Fehler. Oder?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Nein.  Den Fehler gibt's nur in deinem Kopf.  Du hast der
Schrittverfolgung im Debugger (die dich ja nur auf der
Ebene von C-Codezeilen arbeiten lässt) mehr vertraut als
der realen Funktion des generierten Codes.

von Unbekannter (Gast)


Lesenswert?

Wieso? Es stimmt doch alles.

Ausserhalb und innerhalb der Schleife wird doch die gleiche Funktion
aufgerufen. Also passiert bei Ablauf des Codes folgendes:

  1.) Werte für den ersten Funktionsausruf laden.
  2.) Funktion aufrufen.
  3.) Werte für den Funktionsaufruf in der Endlosschleife laden.
  4.) Goto zu Schritt 2.

Alternativ könntest Du das natürlich auch so schreiben:

  1.) Werte für den ersten Funktionsausruf laden.
  2.) Funktion aufrufen.
  3.) Werte für den Funktionsaufruf in der Endlosschleife laden.
  4.) Funktion aufrufen.
  5.) Goto zu Schritt 3.

Das nun hat aber einen unnötigen Schritt zuviel. Also kann man den auch
wegoptimieren...

Und noch lustiger wird es beim gcc-4.x mit Tail-Call-Optimierungen,
besonders in rekursiven Funktionen.
Da kann man dann in C fast schon so wie in LISP programmieren, und
trotzdem gibt's kein Stack-Overflow. ;-)

von Marco G. (macro)


Lesenswert?

OK das leuchtet mir soweit sogar ein. Aber die funktionen werden auch
sozusagen vertauscht ausgeführt.
ich habe einen haltepunkt in die endlosschleife gesetzt. springt der
debugger da hin und lasse ich den nächsten schritt ausführen springt
der debugger aus der schleife führt dabei aber nicht die funktion in
der schleife aus. erst wenn der debugger wieder über die "aussere"
funktion gelaufen ist passiert hardwaremässig das was passieren soll.

und warum ist das kein fehler wenn ich will, dass die "aussere"
funktion nur einmal ausgeführt wird jedoch die "innere" im anschluss
daran ständig und er faktisch beide immerwieder ausführt? dann genau so
läuft das programm ab. beide funktionen werden immerwieder ausgeführt!

von Marco G. (macro)


Lesenswert?

ok jetzt hab ichs tatsächlich verstanden. alles klar. kein fehler! sieht
eben nur so aus. ich finds nutürlich ein wenig bescheurt vom studio,
dass da nicht der sinn des asm-codes verstanden wird und dem benutzter
wenigstens vorgegaukelt wird, dass alles so läuft wie gewünscht.

aber noch was anderes

habt ihr irgendeine idee welche ursachen in frage kommen, wenn
code-teile mal richtig und mal falsch ausgeführt werden
bsp:
variante a: 999938/1000000=0.999938
variante b: 999938/1000000=0.499969

von A.K. (Gast)


Lesenswert?

Der Debugger hat keine Chance. Wo technisch nur ein Funktionsaufruf ist,
hat er naturgemäss Probleme, diesen Aufruf mehreren Quellecodezeilen
zuzuordnen. Das ist der wohlbekannte Pferdefuss bei eingeschalteter
Code-Optimierung des Compilers.

Weshalb in solchem Kontext auch immer der Tip gegeben wird, bei Nutzung
des Debuggers die Code-Optimierung durch den Compiler abzuschalten. Was
bei Controllern freilich bisweilen Grenzen hat, wenn dabei das ROM
platzt.

Die Situation ist also nicht ideal, sie kann es nicht sein. Es kann
sogar das Paradox entstehen, dass ein mies optimierender Compiler im
praktischen Betrieb mit Debuggern angenehmer wirkt als ein gut
optimierender.

von Marco G. (macro)


Lesenswert?

und zum anderen problem gibts keine meinungen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Welches ,,andere Problem''?

von Marco G. (macro)


Lesenswert?

ich hab da noch ein Problem:

"aber noch was anderes

habt ihr irgendeine idee welche ursachen in frage kommen, wenn
code-teile mal richtig und mal falsch ausgeführt werden
bsp:
variante a: 999938/1000000=0.999938
variante b: 999938/1000000=0.499969"

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mach mal einen separaten Thread dafür auf (hier im Forum)
mit einem nachvollziehbaren Programmstückchen.

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.