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
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).
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
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.
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.
@Jörg Ja und was soll ich jetzt tun damit dieser Fehler nicht mehr auftritt? Denn es ist doch wohl ein Fehler. Oder?
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.
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. ;-)
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!
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
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.
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"
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.