Forum: Compiler & IDEs Max RAM bei Xilinx SDK gcc Compiler und MicroBlaze Prozessor


von Andreas N. (poolspieler)


Lesenswert?

Hallo,
ich möchte folgendes Programm auf dem Spartan3E-Starter Board ausführen 
und wundere mich, dass bei einem Build bei globalen Variablen die 
RAM-Überprüfung korrekt ist - bei lokalen Variablen aber nicht.
Ich benutzte nur BRAM - kein externes SD-RAM.
(Ob dieser Thread eher ins FPGA-Forum gepasst hätte, weiß ich nicht... 
;-))


Versuch1 mit globalen Variablen - MIT erwarteter Fehlermeldung:
1
int testarray[10000000]; //wirft wie erwartet einen Fehler
2
3
int main() {
4
  xil_printf("Hallo Welt!");
5
}
--> make
1
**** Incremental build of configuration Debug for project mb0_default ****
2
3
make all 
4
mb-gcc -c -mno-xl-soft-mul -mxl-pattern-compare -mcpu=v7.10.a -I../../microblaze_0_sw_platform/microblaze_0/include -xl-mode-executable -g -O0 -gstabs -olab2.o ../../../code/lab2.c
5
 
6
Building target: mb0_default.elf
7
mb-gcc -o mb0_default.elf lab2.o    -mxl-soft-mul -mxl-pattern-compare -mcpu=v7.10.d  -L../../microblaze_0_sw_platform/microblaze_0/lib -xl-mode-executable   -gstabs
8
Finished building: mb0_default.elf
9
10
************** Validating ELF File **************
11
12
Validating ELF Section Addresses with Hardware Address Map...
13
elfcheck -noheader -mhs C:/Workdir/Xilinx/Tests/Tutorial2/system.mhs -p xc3s500efg320-4 -xmpdir C:/Workdir/Xilinx/Tests/Tutorial2 -pe microblaze_0 mb0_default.elf
14
ERROR:MDT - Section .bss (0x12B0 - 0x2625A33) does not fit completely into
15
   memory dlmb_cntlr (0x0 - 0x3FFF).
16
ERROR:MDT - Section .stack located at address 0x2626CE4 does not map to any
17
   memory found in the hardware design.
18
ERROR:MDT - elfcheck failed!
19
INFO:MDT - Try using the linker script generation tools to generate an ELF that
20
   maps well to your hardware design.
21
make: *** [mb0_default.elf] Error 2
22
Build complete for project mb0_default

Versuch2 mit LOKALER Variable - OHNE Fehlermeldung...???
1
int main() {
2
  int testarray[10000000]; //wirft KEINEN Fehler????
3
  xil_printf("Hallo Welt!");
4
}
--> make:
1
**** Incremental build of configuration Debug for project mb0_default ****
2
3
make all 
4
mb-gcc -c -mno-xl-soft-mul -mxl-pattern-compare -mcpu=v7.10.a -I../../microblaze_0_sw_platform/microblaze_0/include -xl-mode-executable -g -O0 -gstabs -olab2.o ../../../code/lab2.c
5
 
6
Building target: mb0_default.elf
7
mb-gcc -o mb0_default.elf lab2.o    -mxl-soft-mul -mxl-pattern-compare -mcpu=v7.10.d  -L../../microblaze_0_sw_platform/microblaze_0/lib -xl-mode-executable   -gstabs
8
Finished building: mb0_default.elf
9
10
************** Validating ELF File **************
11
12
Validating ELF Section Addresses with Hardware Address Map...
13
elfcheck -noheader -mhs C:/Workdir/Xilinx/Tests/Tutorial2/system.mhs -p xc3s500efg320-4 -xmpdir C:/Workdir/Xilinx/Tests/Tutorial2 -pe microblaze_0 mb0_default.elf
14
elfcheck passed!
15
16
************** Determining Size of ELF File **************
17
18
mb-size mb0_default.elf
19
   text     data      bss      dec      hex  filename
20
   4418      300     1080     5798     16a6  mb0_default.elf
21
22
Build complete for project mb0_default


Das ganze macht mich etwas "unruhig".
Woher soll ich denn nun wissen, ob der RAM für eine lokal definierte 
Variable noch ausreicht - oder nicht?
Hat jemand einen Tip für mich?

Beste Grüße,
Andreas

von Christian R. (supachris)


Lesenswert?

Hm, naja, im Normalfall wandern lokale Variablen ja auf den Heap, 
eventuell überprüft der GCC nicht, wie groß der werden darf?

von Andreas N. (poolspieler)


Lesenswert?

Hallo Christian,
das ist richtig - die wandern auf den Heap.
Wie es aussieht überprüft der gcc tatsächlich nicht wie groß der wird.
Die dicke Frage ist nur, wie kann ich den gcc dazu bringen, dass er es 
tut??

Gruß,
Andreas

von Mark .. (mork)


Lesenswert?

Lokale Variablen werden auf dem Stack und nicht auf dem Heap 
gespeichert.
>wie kann ich den gcc dazu bringen, dass er es tut??
Wahrscheinlich garnicht, denn lokale Variablen werden erst zur Laufzeit 
angelegt. Es müsste aber eine Option geben, die dem Compiler sagt, dass 
er nach jedem Funktionsaufruf überprüft, ob der Stack eventuell 
übergelaufen ist.

MfG Mark

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Das kann der Compiler garnicht pruefen, selbst wenn er wollte. Denn das 
haengt von Parametern wie etwa der Rekursionstiefe Deiner Funktionen ab, 
die wiederum von etwaigen Eingabewerten abhaengen, die zur Compile-Time 
unmoeglich bekannt sein koennen. Ergo musst Du selber dafuer sorgen dass 
Dein Programm die verfuegbaren Ressourcen nicht sprengt. Ein guter Weg 
ist da z.B., auf Rekursion wenn es geht komplett zu verzichten, dann 
bleibt die Sache ueberschaubar.

Michael

von Andreas N. (poolspieler)


Lesenswert?

Hallo Michael,
wenn man genau darüber nachdenkt hast Du recht.
ABER:
Z.B. der CCS-Compiler für PICs gibt nach dem compilieren die minimale 
und maximale RAM-Auslastung aus. Eine Rekursion wird von diesem Compiler 
nicht unterstützt.
Bleibt aber die Frage, wie das dieser CCS-Compiler macht - und warum es 
der gcc (mit den default-Einstellungen vom Xilinx SDK) nicht macht.

Sicherlich ist es beim CCS-Compiler auch nur eine "Schätzung". So weit 
ich aber weiß, "schätzt" er sehr großzügig. Er nimmt also immer den 
schlechtesten Fall an.

In meinem obigen Beispiel ist es doch für den Compiler sehr simpel.
Die funktion main() hat eine lokale Variable, die viel zu groß ist - das 
würde der CCS-Compiler gut erkennen können.

Schwierig wird es natürlich, wenn in einer Unterfunktion eine weitere 
Unterfunktion in Abhängigkeit einer IF-Abfrage oder gar einer 
SWITCH-Abfrage aufgerufen wird. Dann kann der Compiler so einfach 
natürlich nicht mehr den maximalen Speicherbedarf berechnen...


********************  Lösung gefunden (während dem Schreiben hier...) 
*************
Ich habe gerade eine Seite gefunden:
http://www.delorie.com/gnu/docs/gcc/gnat_ug_46.html

Die gcc-Option -fstack-check tut genau das was ich möchte.
Es wird zwar im Fehlerfall nur eine Warnung - kein Fehler geworfen, aber 
das reicht mir so...

Danke für die Anregung und beste Grüße,
Andreas

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Dir ist klar dass die Dokumentation auf den Ada-GCC bezogen ist. Hier 
wird Laufzeit-Code generiert, der prueft, ob noch genug Speicher am 
Stack verfuegbar ist. Sicherlich mit der Konsequenz von nicht 
unwesentlichen Performance-Verlusten. Ausserdem muss man mit einem 
Pragma die Groesse des Stacks angeben. Das funktioniert dann auch nur so 
lange gut, wie die Groesse dieses Stacks bekannt und konstant ist. Unter 
komplexen Systemen ist das aber nicht der Fall, das steht auch dort:

>For the environment task, the stack size depends on system defaults and is
>unknown to the compiler. The stack may even dynamically grow on somesystems,
>precluding the normal Ada semantics for stack overflow. In the >worst case,
>unbounded stack usage, causes unbounded stack expansion resulting in the
>system running out of virtual memory.

Was Du also pruefen musst ist, ob der C-GCC das ueberhaupt kann und wie 
das Feature zu benutzen ist. Und da es sich hier zwangslaeufig um eine 
Laufzeitpruefung handelt bringt es Dir nicht besonders viel. Es hilft 
Dir, bei einem Stack-Overflow den Fehler besser zu finden da hier eine 
spezielle Exception geworfen wird. Ohne diesen Code wuerde Dein Prgramm 
halt einfach abschmieren. Das Feature hilft Dir allerdings nicht, zur 
Compile-Time irgendwelche Schlussfolgerungen auf die Auslastung des 
Stacks zu ziehen.

Ach ja, Ada ist ja "bekannt" fuer solche Dinge. Da wird z.B. auch Code 
generiert, der Array-Zugriffe auf ihre Grenzen hin ueberprueft. Sowas 
wird in C z.B. auch nicht gemacht. Da rauscht Dir im Zweifelsfall halt 
Dein Programm ab.

Michael

von Andreas N. (poolspieler)


Lesenswert?

Michael G. wrote:
> Dir ist klar dass die Dokumentation auf den Ada-GCC bezogen ist.
Ja, ist mir klar - das war halt die erste Seite, auf der diese 
Compileroption beschrieben war...

> Hier wird Laufzeit-Code generiert, der prueft, ob noch genug Speicher am
> Stack verfuegbar ist. Sicherlich mit der Konsequenz von nicht
> unwesentlichen Performance-Verlusten. Ausserdem muss man mit einem
> Pragma die Groesse des Stacks angeben. Das funktioniert dann auch nur so
> lange gut, wie die Groesse dieses Stacks bekannt und konstant ist. Unter
> komplexen Systemen ist das aber nicht der Fall, das steht auch dort:
>>For the environment task, the stack size depends on system defaults and is
>>unknown to the compiler. The stack may even dynamically grow on somesystems,
>>precluding the normal Ada semantics for stack overflow. In the >worst case,
>>unbounded stack usage, causes unbounded stack expansion resulting in the
>>system running out of virtual memory.
>
> Was Du also pruefen musst ist, ob der C-GCC das ueberhaupt kann und wie
> das Feature zu benutzen ist. Und da es sich hier zwangslaeufig um eine
> Laufzeitpruefung handelt bringt es Dir nicht besonders viel. Es hilft
> Dir, bei einem Stack-Overflow den Fehler besser zu finden da hier eine
> spezielle Exception geworfen wird. Ohne diesen Code wuerde Dein Prgramm
> halt einfach abschmieren. Das Feature hilft Dir allerdings nicht, zur
> Compile-Time irgendwelche Schlussfolgerungen auf die Auslastung des
> Stacks zu ziehen.
Ich habe es bereits mit obigem Beispiel ausprobiert.
Im Fehlerfall (also zu große Variable) wird eine Compiler-Warnung 
ausgegeben. Die Größe des Stacks habe ich nicht explizit angeben müssen. 
Die wird ja dem MicroBlaze mitgeteilt - vor der Synthese (in meinem Fall 
die BRAM-Größe - hab ja kein DDR-RAM). Der gcc hat sich anscheinend 
automatisch diese Information geholt... Ansonsten hätte er ja auch keine 
Fehlermeldung für die globale Variable werfen können...


Gruß,
Andreas

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Eine globale Variable kommt nicht auf den Stack, das hat damit garnichts 
zu tun. Das ist aber auch einleuchtend, weil es fuer globale Objekte 
immer nur genau eine Inkarnation geben kann, die nicht vom Scope 
abhaengt. Diese also auf den Laufzeit-Stack zu werfen waere fatal.

von Andreas N. (poolspieler)


Lesenswert?

Du hast (mal wieder) recht.
Ich sollte mir mal wieder die Begrifflichkeiten Heap, Stack und Co. 
anschauen - ist doch schon alles zu lange her...

Bei der globalen Variable kommt die Fehlermeldung tatsächlich nicht vom 
gcc, sonder von dem Programm "elfcheck".

Woher nun der gcc die maximale Stackgröße hergenommen hat, weiß ich 
gerade auch nicht - werde es mir aber die kommenden Tage nochmal 
anschauen...

Danke für die Infos und schönen Feieraben... ;-)

Andreas

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Andreas N. wrote:

> Woher nun der gcc die maximale Stackgröße hergenommen hat, weiß ich
> gerade auch nicht - werde es mir aber die kommenden Tage nochmal
> anschauen...

Er ist einfach von einem default-value ausgegangen. Das kann Dir dazu 
fuehren dass Dein Programm terminiert, obwohl noch genug Stack zur 
Verfuegung stehen wuerde. Da solltest Du etwas vorsichtig mit sein, vor 
allem wenn Du nicht weisst, wie dieses default gesetzt ist.

Michael

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.