Forum: Compiler & IDEs Nicht genutzte globale Variablen werden wegoptimiert


von Oliver B. (irq)


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:
1
/* Keine dieser Varianten funktioniert */
2
uint32_t test = 5;
3
//volatile uint32_t test = 5;
4
//const uint32_t test = 5;
5
//static const uint32_t test = 5;
6
7
int main(void) {
8
 code
9
 code
10
 /* Irgendwo ein Breakpoint um mal in den Speicher zu schauen */
11
 code
12
}

Jetzt das Gleiche mit einer Verwendung:
1
int main(void) {
2
 code
3
 /* Breakpoint */
4
 code
5
 uint32_t asdf = test; 
6
 code
7
}

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
1
extern uint32_t _isr_vectorsflash_offs;
2
void NVIC_Configuration(void) {
3
 NVIC_SetVectorTable(NVIC_VectTab_FLASH, (uint32_t)&_isr_vectorsflash_offs);
4
}
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:
1
C_FLAGS = -mcpu=cortex-m3 -mthumb -O0 -gdwarf-2 \
2
          $(patsubst %,-I%,$(INC_DIRS)) -I. \
3
          -std=gnu99 \
4
          -ffunction-sections -fdata-sections \
5
          -Wall -Wextra -Wimplicit -Wcast-align -Wpointer-arith \
6
          -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -Wnested-externs \
7
          -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.

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


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.

von (prx) A. K. (prx)


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.

von Oliver B. (irq)


Angehängte Dateien:

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:
1
. = ALIGN(0x80);
2
KEEP(*(.bl_jump))
3
    
4
. = 4k; /* Hier springe ich erst mal nach Offset = 4096
5
    
6
. = ALIGN(0x80); /* Tut nichts, da ja schon richtig aligned */
7
_isr_vectorsflash_offs = . - 0x08000000;
8
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.

von (prx) A. K. (prx)


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.

von Oliver B. (irq)


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.

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.