Forum: Compiler & IDEs GCC ( AVRStudio 6.2.933.beta) optimiert lokale variable weg


von Hans-Georg L. (h-g-l)


Lesenswert?

Ich stehe im Moment gerade etwas auf dem Schlauch ...


Wenn ich mit dem Debugger in dem folgenden Code lande erzählt mir das 
Atmel Studio regNum wäre wegoptimiert und ich kann mir die Variable 
nicht anschauen.


bool ReadRegisterCmd(uint8_t * regValue)
{
  uint8_t regNum = uart_getc();

  if( (regNum >=0) && (regNum <= 0x29) )
  {
    return AD9854_ReadRegister(regNum, regValue);
  }

  return 0;
}

1. Darf der Compiler das ?
2. Ich kenne von anderen Compilern, das im Debug Mode nichts optimiert 
wird.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ja, er darf es.

Und eherned Gesetz bei GCC ist, daß die Debig-Einstellungen keinen 
Einfluß auf den erzeugten Code haben dürfen.

von J. Eder (Gast)


Lesenswert?

Optimierung ausschalten ?
Debugmodus bedeutet nur das die Zusatzinfos nicht entfernt werden bzw. 
überhaupt generiert werden.

von Steffen R. (steffen_rose)


Lesenswert?

Wenn Du sicher Variablen beim Debuggen ansehen willst, setze sie 
volatile. Vergiss aber hinterher nicht, dies wieder zu entfernen.

Mit aktiver Optimierung wird es aber eh' schwierig zu debuggen.

von Hans-Georg L. (h-g-l)


Lesenswert?

Dankeschön an alle :)

Gibt es bem Atmel Studio so etwas wie #define DEBUG, wenn die Debug 
Configuration ausgewählt ist, das man abfragen kann ?

von Stefan (Gast)


Lesenswert?

Schalt die Optimierung aus wenn du Debuggen willst. Dafür muss man nun 
kein Konstrukt dafür bauen.
Aber der Cimpiler liefert dir das Define zum abfragen

von Hans-Georg L. (h-g-l)


Lesenswert?

Stefan schrieb:
> Schalt die Optimierung aus wenn du Debuggen willst. Dafür muss man nun
> kein Konstrukt dafür bauen.
> Aber der Cimpiler liefert dir das Define zum abfragen

Dann ist ja gut ;)

Das #define kann man halt im Code da einfügen wo man möchte, die globale 
Optimierung ein/aus ist da nicht so selektiv.

Stell dir vor, du hast ein Programm, das ab und zu in einen 
Fehlerzustand läuft. Das ist es doch sinnvoll das Programm optimiert in 
Echtzeit laufen zu lassen bis der Debugger hardwaremässig feststellt, 
das eine bestimmte Programmadresse (Die Fehlerbehandlung Routine) 
erreicht wurde. Da willst du jetzt aber alle deine lokalen Variablen 
anschauen und nicht wegoptimiert haben.

Und für Trace Ausgaben und Diagnose Meldungen benutz ich das immer 
wieder gerne. Man darf halt nicht nur einen 8 Bit Controller mit seinen 
beschränkten Resourcen betrachten.
Und ich arbeite ja nicht nur mit GCC und mit AVRs.

Aber in diesem einen Falle hätte es natürlich mit Aus/Einschaltung der 
Optimierung funktioniert.

von Karl H. (kbuchegg)


Lesenswert?

Hans-Georg Lehnard schrieb:

> Stell dir vor, du hast ein Programm, das ab und zu in einen
> Fehlerzustand läuft. Das ist es doch sinnvoll das Programm optimiert in
> Echtzeit laufen zu lassen bis  ...

Das ist generell immer ein Problem.
Denn auf der einen Seite möchte man natürlich möglichst exakt das 
Programm im Debugger laufen sehen, dass auch in echte läuft. Auf der 
anderen Seite benötigt der Debugger natürlich auch Information, damit er 
möglichst dem Programmierer entgegen kommen kann und ihm die aus dem 
Programm rausgezogene Information in einer dem Programm angepassten Form 
präsentiert.

> der Debugger hardwaremässig feststellt,
> das eine bestimmte Programmadresse (Die Fehlerbehandlung Routine)
> erreicht wurde. Da willst du jetzt aber alle deine lokalen Variablen
> anschauen und nicht wegoptimiert haben.

Na, ja. Ganz so ist es ja nicht.
Der Wert existiert im laufenden Programm. Nur gibt es keine 
Speicherstelle in die er zwischendurch mal geparkt wird. Aber 
grundsätzlich muss ja der Wert, den die Funktion von uart_getc() kriegt, 
irgendwo sein. Wenn es keine Variable dafür gibt, dann lungert der in 
irgendeinem Register rum. Das wird auch immer wieder dasselbe Register 
sein.
d.h. wenn dein Hardware-Debugger dir die Möglichkeit gibt, dir die 
Prozessor-Register anzusehen, dann wirst du dort in irgendeinem Register 
das Ergebnis des uart_getc wieder finden. Und es wird auch in jedem 
Programmlauf das immer gleiche Register sein. Unter Umständen muss man 
dann auch ein wenig den Assembler Code studieren, um rauszufinden 
welches Register das ist.

Ein Debugger, der erst mal nur mit dem arbeitet, was ihm der Compiler an 
Informationen hinterlassen hat, wird da natürlich nicht fündig. Da muss 
man dann schon als Entwickler selbst ein wenig nachhelfen und darf sich 
nicht scheuen, auch mal in die tieferen Gefilde runterzusteigen.

von Hans-Georg L. (h-g-l)


Lesenswert?

Karl Heinz schrieb:
>
> Ein Debugger, der erst mal nur mit dem arbeitet, was ihm der Compiler an
> Informationen hinterlassen hat, wird da natürlich nicht fündig. Da muss
> man dann schon als Entwickler selbst ein wenig nachhelfen und darf sich
> nicht scheuen, auch mal in die tieferen Gefilde runterzusteigen.

Genau das wollte ich ja, dem Debugger die Information hinterlassen wo 
ich gerne die meine information zum Lesen hätte, damit ich nicht lange 
herumsuchen muss, aber der Compiler wollte nicht und hat es 
wegoptimiert.

Das man irgendwann mal ganz tief unten suchen muss, keine Frage ...

von lex (Gast)


Lesenswert?

Karl Heinz schrieb:
> Und es wird auch in jedem
> Programmlauf das immer gleiche Register sein. Unter Umständen muss man
> dann auch ein wenig den Assembler Code studieren, um rauszufinden
> welches Register das ist.

Zumindest das Dwarf Debugging Format unterstützt verschiedene Arten von 
Adressierungen. Neben stack-relativ können auch Register angegeben 
werden.
Wenn du also im Debugger dir die betreffende Variable ansehen willst 
kann es durchaus sein, dass der Wert der dir angezeigt wird nicht 
irgendwo vom Stack sondern aus einem Register gelesen wird. Für dich ist 
das völlig transparent. Du siehst dir einfach die Variable an, und 
brauchst eigentlich nicht zu wissen, wo diese nun genau im Speicher 
liegt. Wie gesagt, Dwarf bietet diese Möglichkeit.
D.h. du kannst dir grundsätzlich auch "wegoptimierte" Variablen ansehen, 
denn wegoptimiert kann auch bedeuten dass der Wert lediglich in einem 
Register gehalten wird.

Soweit die Theorie. Ob dein Compiler diese Information auch generiert 
bzw. dein Debugger sie auswerten kann, ich weiß es nicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

lex schrieb:
> Wie gesagt, Dwarf bietet diese Möglichkeit.
> D.h. du kannst dir grundsätzlich auch "wegoptimierte" Variablen ansehen,
> denn wegoptimiert kann auch bedeuten dass der Wert lediglich in einem
> Register gehalten wird.
>
> Soweit die Theorie. Ob dein Compiler diese Information auch generiert
> bzw. dein Debugger sie auswerten kann, ich weiß es nicht.

Offenbar wird das von den Debuggern nicht unterstützt, denn gcc erzeugt 
entsprechende Infos selbst für Variablen, die wegoptimiert sind.

Etwa:
  
1
void fun (void)
2
{
3
    int bummer = 123;
4
}
5
6
int main()
7
{
8
    return 0;
9
}


und das übersetzen mit:

$ avr-gcc foo.c -Os -g2 -save-temps -o foo.elf
$ avr-readelf  -w foo.elf

Wie man im s-File sieht, ist die Variable wegoptimiert und die Funktion 
enhält nur noch ein RET, (Debug)-Labels und Kommentare:
 
1
fun:
2
.LFB0:
3
  .file 1 "foo.c"
4
  .loc 1 2 0
5
  .cfi_startproc
6
/* prologue: function */
7
/* frame size = 0 */
8
/* stack size = 0 */
9
.L__stack_usage = 0
10
.LVL0:
11
  ret
12
  .cfi_endproc
13
.LFE0:
14
  .size  fun, .-fun

In der readelf-Ausgabe hingegen steht unser bummer samt Wert und Typ:
  
1
 <2><3a>: Abbrev Number: 3 (DW_TAG_variable)
2
    <3b>   DW_AT_name        : (indirect string, offset: 0x0): bummer  
3
    <3f>   DW_AT_decl_file   : 1  
4
    <40>   DW_AT_decl_line   : 3  
5
    <41>   DW_AT_type        : <0x47>  
6
    <45>   DW_AT_const_value : 123  
7
 <2><46>: Abbrev Number: 0
8
 <1><47>: Abbrev Number: 4 (DW_TAG_base_type)
9
    <48>   DW_AT_byte_size   : 2  
10
    <49>   DW_AT_encoding    : 5  (signed)
11
    <4a>   DW_AT_name        : int

von Steffen R. (steffen_rose)


Lesenswert?

Beim TO wird die lokale Variable benutzt. Daher ist davon auszugehen, 
dass sie nicht komplett wegoptmiert wurde, sondern in Registern gehalten 
wird.

Mit ein paar besseren Optionen wäre die gesamte Funktion fun() 
weggefallen.

von lex (Gast)


Lesenswert?

Eben. Ich trau mich wetten dass die Variable im Dwarf-Teil des .elf noch 
auftaucht, und zwar mit einem Register als Speicherort. Readelf würde da 
Klarheit bringen. Wenn der TO seine .elf anhängen würde könnte man das 
nachprüfen.
Höchstwahrscheinlich wird der Atmel Debugger diese Information einfach 
nicht verwerten.
Evtl. könnte man mit gdb eine Gegenprobe machen.

von Hans-Georg L. (h-g-l)


Lesenswert?

Wie alle Diskussion hier ist das mal wieder ein Selbstläufer, meine 
Fragen sind ja schon längst beantwortet ...

Ich schiebe meine Variablen, die ich sehen will ins "Watch" Fenster und 
step durch mein Programm.

Ich will nicht ein extra Kommandozeilentool (readelf) anwerfen um mir 
das Register zu suchen wo die Variable nun tatsächlich steht. Das ist 
mir einfach viel zu umständlich.

von Steffen R. (steffen_rose)


Lesenswert?

Das elf-File sollte nur Klarheit bringen, ob die Variable, wie im 
Betreff geschieben, wegoptimiert wurde (wie in Johanns Beispiel). Oder 
ob diese, wie eher zu vermuten ist, in Register abgelegt wurde.

von Ein (Gast)


Lesenswert?

Hans-Georg Lehnard schrieb:
> Ich will nicht ein extra Kommandozeilentool (readelf) anwerfen um mir
> das Register zu suchen wo die Variable nun tatsächlich steht. Das ist
> mir einfach viel zu umständlich.

... was meinst du, wie dein GCC gestartet wird.

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.