www.mikrocontroller.net

Forum: Compiler & IDEs Größe vom Stack/Heap?!


Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Wer die Vorgeschichte nicht lesen mag, überspringt einfach den
folgenden Absatz und liest nur die letzte Zeile.

Ich programmiere einen Mega32 in C mit avrgcc und habe folgendes
Problem: Große structs (16 Byte groß), die ich an Funktionen übergebe,
kommen nicht korrekt "an". d.h. in den funktionen unterscheiden sich
die Daten von denen, die ich übergeben habe (übergabe by value!)
Als Problem konnte ich die Größe des Stacks oder Heaps ausmachen (ich
weiss nicht so genau was der Unterschied ist, aber soviel ich weiss
werden ja Werte an Funktionen übergeben in dem sie vorher auf den Stack
gepushed werden).
Kompilierte ich das Program mit IARCC, lief es zunächst auch nicht
korrekt. Irgendwo habe ich dann eine Option gefunden, mit der man dem
Stack und Heap mehr Platz zuweisen konnte und schon lief das Programm
so wie es sollte.
Mit dieser Info habe ich einfach das Programm so geändert, daß diese
Structs per Referenz übergeben werden und prompt lief es dann wie
erwartet auch mit avr-gcc.

Die Frage ist jetzt einfach, wie ändere ich die Größe des Stracks
und/oder Heaps auch unter avr-gcc?

Vielen Dank!
Markus

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gar nicht.  Beide sind von Haus aus auf Maximum eingestellt, und da
der GCC im Gegensatz zu IAR & Co. nur einen Stack benutzt (und nicht
zwei), braucht man da nichts einzustellen.  (Beim IAR ist meines
Wissens einer der beiden Stacks automatisch, der andere muß vorher
festgelegt werden.  Einer ist dort der Call-Stack, der andere der
Parameter-Stack.)

Debugge Dein Problem lieber mal, indem Du Dir den Assemblercode
ansiehst, den der Compiler generiert.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
leider wüsste ich dann nix damit anzufangen bzw würde nicht herausfinden
können, was schief läuft...

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, dann sind Microcontroller vermutlich kein richtiges
Betätigungsfeld für Dich, sorry.

Dir kann gern geholfen werden, wenn Du Fragen hast, aber Deinen Teil
an der Arbeit mußt Du schon selbst tun.  Auch wenn man MCUs
mittlerweile prima in C programmieren kann, so funktioniert das
trotzdem nicht, wie auf einem Universalcomputer, einerseits wegen der
oft nötigen Hardwarenähe (die bestenfalls vergleichbar mit
Betriebssystemprogrammierung auf Universalcomputern ist), andererseits
wegen der sehr beschränkten Ressourcen.  Wirkliches Debuggen auf einer
MCU ist sehr viel aufwendiger als auf einem Universalcomputer.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
naja ich wollte damit nicht sagen, daß ich den ASM Code nicht verstehe.
Im Prinzip kann es sich ja nur um einen Bug im GCC handeln (denke ich
zumindest) denn RAM ist ja genug da. Was soll ich denn tun, wenn ich
jetzt feststelle daß da irgendwas im Nirvana aufgrund falschem Code
verschwindet?
Man kann das Problem auch nicht immer nachvollziehen, denn ändere ich
irgendwas an irgendeiner Funktion verhält es sich dann total anders.
Was z.B. auch jedesmal bei mir zu einem Fehler führt ist eine for
Schleife rückwärts laufen zu lassen.
als sowas wie "for (i=10, i>=0, i--)", hingegen "for (i=0, i<10,
i++)" funktioniert. Ich kann mir eigentlich nicht vorstellen, daß das
noch niemand anderem aufgefallen ist (ich habe aber auch noch für
dieses Problem nicht gesucht ob dieser Bug schon existiert).
Leider weiss ich nicht, wie ich diese Probleme debuggen kann, denn ich
interagiere eigentlich immer mit anderer Hardware und die kann ich
nicht simulieren. z.B. ist dieses 15 Byte struct in meiner ersten
Message eine komplette CAN Message, die ich einfach nur auf den Bus
sende und dann wieder empfange und dann auf dem Display anzeige. Du
kannst dir natürlich vorstellen, daß ich immer gedacht habe, daß die
Message falsch übertragen wird (also der Fehler bei mir in der
Ansteuerung des CAN Controllers liegt). Bis ich darauf gekommen bin das
die Nachricht korrekt gesendet und empfangen wird sondern nur aufgrund
dieses Parameterübergabebugs falsch angezeigt wird hats ganz schön
gedauert (die empfangene Nachricht ins EEPROM zu speichern hat
lustigerweise korrekt funktioniert).

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> naja ich wollte damit nicht sagen, daß ich den ASM Code nicht
> verstehe.

Wenn Du ihn verstehst, kannst Du aber auch nachvollziehen, was der
Compiler tut.  Ist mühselig, aber machbar.

> Im Prinzip kann es sich ja nur um einen Bug im GCC handeln

Vorsicht, Grundregel #1: rede erst dann über einen Bug in fremder
Software, wenn Du Dir durch eine Analyse sicher geworden bist, daß es
sich wirklich um einen solchen handelt.  99,9 % aller vermuteten Bugs
sitzen vor der Tastatur. ;-)

> Man kann das Problem auch nicht immer nachvollziehen, ...

Das ist genau die Schwierigkeit beim Debuggen von MCU-Software
schlechthin.  Du hast eben anschaulich dargelegt, warum Simulation zur
Erkennung des Problems ohnehin nur marginal tauglich ist (eigentlich
nur für sehr einfache externe Einwirkung oder für das Debuggen von
Algorithmen), Du mußt also auf andere Methoden zurückgreifen.  Neben
der schon erwähnten Codeanalyse kommen noch in Frage: JTAG-Emulation
(ist aber natürlich auch nicht völlig echtzeitfähig), ,,printf''
Debugging, LED-Tests, bei vermuteten stack-heap-Kollisionen verbunden
mit einem Initialisierungsmuster im gesamten RAM, anhand dessen der
,,Füllstand'' des Stack gelegentlich (z. B. via printf)
nachvollzogen
wird.

Meines Wissens werden structs bei der Übergabe auf dem Stack abgelegt
(einfache Variablen werden für gewöhnlich in Registern übergeben).
Damit ist es also gut möglich, daß Dein Stack überläuft.  Die Details
der Übergabe dieser structs sind gut aus dem Assemblercode ersichtlich
(s. o.).

Meine Vermutung ist, daß Dir aus irgendwelchen Gründen (z. B. zu viele
Strings) der RAM alle wird.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Was z.B. auch jedesmal bei mir zu einem Fehler führt ist eine for
> Schleife rückwärts laufen zu lassen.
> als sowas wie "for (i=10, i>=0, i--)"

Das ist ein beliebter Fehler, wenn i unsigned ist, dann ist das eine
Endlosschleife.

Ansonsten teste ich Sachen, wo ich mir nicht sicher bin, einfach mal
unter Borland-C. Ich nehme da die Version in der DOS-Box, damit man
sich nicht mit dem Windows-Schrunz rumplagen muß.

Denn dazu ist es ja C, daß es auch auf anderen Maschinen läuft.

Und erst, wenn es unter Borland-C läuft, aber unter WINAVR nicht, dann
könnte es ein Bug im Compiler sein.


Peter

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg:
>> naja ich wollte damit nicht sagen, daß ich den ASM Code nicht
>> verstehe.

>Wenn Du ihn verstehst, kannst Du aber auch nachvollziehen, was der
>Compiler tut.  Ist mühselig, aber machbar.

Wie gesagt, es handelte sich hier um eine CAN Message, die zuvor vom
CAN Controller geladen wurde. Ich kann mir ja beim nachvollziehen des
ASM Codes nicht sicher sein, ob da schon was falsch gelesen wird (das
ändert natürlich den Inhalt der Speicherstellen der Variablen, etc.)
oder eben erst später das Problem bei der Übergabe durch den Stack
auftritt. Das macht es ja so schwierig für mich, das nachzuvollziehen.
Und JTAG habe ich leider nicht zur Verfügung.
Desweiteren ist es in der Tat viel Arbeit und da es mit Übergabe als
Referenz funktioniert fehlt mir ehrlich gesagt die Motivation mir das
genau anzuschauen. Ich hatte ursprünglich ja auch gedacht das mit einem
einfachen Kompilerparamter lösen zu können.

Ausserdem habe ich ja nicht nach Bug geschrien, sondern das nur in
Erwägung gezogen, weil es unter IAR quasi ohne weitere Probleme lief.
Von daher schliesse ich auch aus, daß mir der Speicher ausgeht. Denn
der müsste unter IAR dann genauso ausgehen (zumindest müsste das
Programm IMHO dann auch nicht korrekt laufen, wenn auch warscheinlich
mit anderem Fehler).

@Peter:
>Das ist ein beliebter Fehler, wenn i unsigned ist, dann ist das eine
>Endlosschleife.

Natürlich, das wirds gewesen sein ;-). Mit normalem gcc für x86
kompiliert habe ich natürlich stets "int" genommen und beim AVR nehme
ich eigentlich immer "uint8_t".

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Von daher schliesse ich auch aus, daß mir der Speicher ausgeht. Denn
> der müsste unter IAR dann genauso ausgehen

Das ist ein Trugschluß.  Meines Wissens kann der IAR z. B. alle string
literals (also Texte, die in "" stehen) automatisch in den ROM
plazieren (was ihn dann nicht mehr standardkonform macht, da man
solche Strings nicht an Standard-Funktionen aus <string.h> übergeben
kann).  Der GCC plaziert die Strings dagegen immer im RAM.

Ohne genaue Zahlen Deinerseits gibt's da aber auch keine Hilfe.

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>@Peter:
>>Das ist ein beliebter Fehler, wenn i unsigned ist, dann ist das eine
>>Endlosschleife.
>
>Natürlich, das wirds gewesen sein ;-). Mit normalem gcc für x86
>kompiliert habe ich natürlich stets "int" genommen und beim AVR
nehme
>ich eigentlich immer "uint8_t".

Dabei erzeugt gcc aber eine Warnung:
mycode.c:50: warning: comparison is always true due to limited range of
data type

Warnungen sollten immer als Hilfe und nicht als lästig betrachtet
werden. Eine Warnung sollte höchstens dann akzeptiert werden, wenn
genau klar ist, warum sie entsteht und es wirklich keinen Workaround
gibt.

Dein Problem sieht wirklich sehr nach Stackproblem aus. Lies Dir mal im
avr-libc Reference Manual das Kapitel 5.5, "Program Space String
Utilities" durch und bau Dein Programm entsprechend um. Zum
Vorab-Test, ob daran das Problem liegt: Etliche Strings radikal
kürzen.

Das Übergeben einer struct als call-by-value würde ich nach Möglichkeit
vermeiden: es erzeugt wesentlich mehr Code/Abarbeitungszeit.

Stefan

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan&Jörg
Wie meint Ihr das mit dem radikal kürzen? Das Problem trat selbst dann
auf, wenn ich ein "Minimalprogramm" hatte, was wirklich nichts
anderes tut als eine Nachricht zu senden, zu empfangen und diese dann
auf dem Display auszugeben. Die Ausgabe besteht einfach darin, jedes
Byte der Nachricht in Hex auf dem Display darzustellen. Hab mir dazu
extra Funktionen geschrieben, die einen 8Bit Wert in Hex oder Binär
aufs Display schreiben.
Dieses Programm enthielt keinerlei Strings wie "dies ist jetzt ein
Test" , oder sowas.

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Dieses Programm enthielt keinerlei Strings wie "dies ist jetzt ein
>Test" , oder sowas.

Tja, wenn es das nicht war, dann hilft nur noch raten ... oder mal den
Source posten.

Stefan

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.