mikrocontroller.net

Forum: Compiler & IDEs Nicht genutzte globale Variablen werden wegoptimiert


Autor: Oliver B. (irq)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo GCC-Gemeinde,

ich bin gerade auf ein sehr merkwürdiges Problem gestoßen. Und zwar 
werden globale Variablen, die ich in meinem Programmcode nicht explizit 
verwende, nicht richtig initialisiert, d.h. mit unbestimmten Werten. 
Minimalbeispiel:
/* Keine dieser Varianten funktioniert */
uint32_t test = 5;
//volatile uint32_t test = 5;
//const uint32_t test = 5;
//static const uint32_t test = 5;

int main(void) {
 code
 code
 /* Irgendwo ein Breakpoint um mal in den Speicher zu schauen */
 code
}

Jetzt das Gleiche mit einer Verwendung:
int main(void) {
 code
 /* Breakpoint */
 code
 uint32_t asdf = test; 
 code
}

Und siehe da - nun wird die Variable test korrekt initialisiert. Ich 
schließe daraus, dass mein Linker-Skript und der Startup-Code richtig 
ist, da prinzipiell funktioniert die Initialisierung ja.

Weiß jemand, wo der Fehler liegen könnte? Die Optimierung ist jedenfalls 
auf 0 gestellt (-O0).

Man stellt sich natürlich jetzt die berechtigte Frage, wozu mich das 
überhaupt interessiert, wenn ich die Variable eh nicht verwende, 
allerdings war das oben ja ein Minimalbeispiel. Falls es konkret von 
Bedeutung ist:

Ich setze in meinem Linker-Skript ein Symbol an der Position, wo sich 
eine Vektortabelle für nen Cortex-M3 befindet und möchte im laufenden 
Betrieb die NVIC-Tabelle wechseln. Das geht dann mit
extern uint32_t _isr_vectorsflash_offs;
void NVIC_Configuration(void) {
 NVIC_SetVectorTable(NVIC_VectTab_FLASH, (uint32_t)&_isr_vectorsflash_offs);
}
so habe ich das im Code für den STM32 MINI Digital Picture Frame von 
Martin Thomas gefunden. Warum das & an den Funktionsparameter muss, ist 
mir nicht ganz klar. Jedenfalls steht in _isr_vectorsflash_offs ständig 
0x20005000, was definitiv nicht die Position der Vektortabelle im Flash 
ist.

Vielleicht könnte ich das jetzt mit einer Fake-Verwendung der Variablen 
umgehen, das habe ich noch nicht probiert, das wäre aber eh eine mehr 
oder weniger unbefriedigende Lösung.

Ach ja: Die Optimierung ist natürlich aus, hier meine GCC-Argumente aus 
dem Makefile:
C_FLAGS = -mcpu=cortex-m3 -mthumb -O0 -gdwarf-2 \
          $(patsubst %,-I%,$(INC_DIRS)) -I. \
          -std=gnu99 \
          -ffunction-sections -fdata-sections \
          -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith \
          -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs \
          -Wno-cast-qual -Wno-missing-prototypes  -Wno-strict-prototypes -Wno-missing-declarations

Kann mir jemand das Verhalten erklären oder weiß Abhilfe?

Vielen Dank und viele Grüße, Oliver.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver Behr schrieb:
> Ich
> schließe daraus, dass mein Linker-Skript und der Startup-Code richtig
> ist, da prinzipiell funktioniert die Initialisierung ja.

Ich nicht.  Du hast einmal eine globale Variable, die ist auf den
Startup-Code zur Initialisierung angewiesen.  Der funktioniert
vermutlich nicht richtig, daher erhälst du zufällige (und nicht
etwa "wegoptimierte") Werte.

Das zweite ist eine automatische Variable, die vom Compiler durch
expliziten Code beim Eintritt in den Block initialisiert wird.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es kann tatsächlich vorkommen, dass Variablen, die nirgends verwendet 
werden, vom Linker rausgeworfen werden. Allerdings ist das sein gutes 
Recht und wieso dich das stört kann ich trotz deiner übrigen 
Ausführungen nicht nachvollziehen.

Dein Aufruf der Funktion NVIC_SetVectorTable setzt das Vektorregister 
des CM3 auf die Adresse der Variablen _isr_vectorsflash_offs, bzw. 
versucht es, soweit das mit den Restriktionen dieses Registers konform 
geht. Ich habe nicht den Eindruck, dass es dies ist, was du willst. 
Insbesondere wird dadurch natürlich der Inhalt der Variablen in keiner 
Weise verändert.

Wenn diese 0x20005000 die zukünftige Adresse der Vektortabelle sein 
soll, dann ist das "&" falsch - und das "(uint32_t)" davor überflüssig.

Autor: Oliver B. (irq)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Kommentare. Ich habe noch etwas rumgespielt und bin 
nun zu folgenden Ergebnissen gestoßen:

1) Der Wert der Variablen _isr_vectorsflash_offs beträgt nach wie vor 
0x20005000
2) Springe ich beim Debuggen jedoch in die Funktion 
NVIC_SetVectorTable(), so beträgt Offset = 4096k, was absolut gewünscht 
ist, wenn man sich den entsprechenden Teil meines Linkerscripts (nur zum 
Testen) ansieht:
. = ALIGN(0x80);
KEEP(*(.bl_jump))
    
. = 4k; /* Hier springe ich erst mal nach Offset = 4096
    
. = ALIGN(0x80); /* Tut nichts, da ja schon richtig aligned */
_isr_vectorsflash_offs = . - 0x08000000;
KEEP(*(.isr_vector))    

Scheinbar ist das & schon richtig, aber ich weiß absoult nicht warum. 
Ist die Bedeutung hier eine andere, als der Adressoperator? Hängt das 
vielleicht mit dem Modifier extern zusammen? Warum wird es immer auf 
0x20005000 gesetzt, unabhängig davon, wo ich die Vektortabelle 
hinschiebe?

Ich habe mal mein komplettes Linkrscript und relevante Dateien angefügt, 
vielleicht hilft das ja was.

Viele Grüße, Oliver.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So sieht das auch schon anders aus. _isr_vectorsflash_offs ist keine 
echte Variable, sondern ein vom Linker definiertes Symbol. Dessen 
Adresse ist die Adresse der Vektortabelle, der Inhalt ist irrelevant.

Daher ist das "&" durchaus korrekt. Andererseits ergibt es keinen Sinn, 
mit dem Debugger den Inhalt dieser Nicht-Variablen zu analysieren.

Autor: Oliver B. (irq)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann ist mir das auch klar. Ich bin davon ausgegangen, dass der 
Inhalt des Linker-Symbols die Adresse ist und nicht die Symbol-Adresse 
die Adresse der Speicherstelle. Danke für die Aufklärung.

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.