[WinAVR] Stackverseuchung durch main() vermeiden

#3503346
Lesenswert?

Gibt es eigentlich probate 'best practice' Wege zu unterbinden, dass der 
main() Aufruf das Ram mit nutzlosem Stackmüll verschwendet?

Bei meinem letzten Projektchen auf einem ATtiny13 behalf ich mir durch:
1
int
2
__attribute__ ((naked)) // verhindert dass Register auf dem Stack "gesichert" werden
3
__attribute__ ((section (".init8")))  // umgeht Aufruf per rcall, spart 2 Bytes Stack Ram 
4
main(void) {
5
  while (1) {
6
    //...
7
  }
8
  return 0; 
9
}

Natürlich darf man so keine Rekursion auf main mehr aufrufen, weil wegen 
'naked' keine Register gerettet werden. Aber wer will das schon.
Auch darf main() niemals zu Ende laufen, denn diese Funktion geht ja 
davon aus per rcall aufgerufen worden zu sein. Durch ".init8" wird der 
Code von main() aber direkt vor dem üblichen rcall auf main() eingefügt. 
Also rennt das Programm schon in main() rein, bevor es zu diesem rcall 
gelangt. Somit wird auch keine Rücksprungaddresse auf den Stack gelegt. 
Eigentlich ist das ja dreckig, aber wegen der Endlosschleife in main() 
auch nicht relevant.

Ist der Weg gut? Gibt es bessere? Wie vermeidest Du Verschwendung von 
Ram?
Gast #3503493
Lesenswert?

Hallo,

Wenn du diese paar Bytes ganz dringend braucht und es gar keine 
Möglichkeit gibt auf einen größeren Controller zu wechseln, dann lohnt 
sich der Aufwand.

Ansonsten ist es ziemlich nutzlos und reine Verschwendung von Zeit. 
Außerdem holst du dir damit mit, mit ein wenig Pech, neue Fehlerquellen 
an Bord.

Schreibst ja selber dass Rekursion so nicht geht. Mal davon abgesehen, 
dass man so was mit den eng begrenzten  Mitteln eines kleinen uC eher 
vermeiden sollte.


Grüße
#3503677
Lesenswert?

Achim K. schrieb:
>
1
> int __attribute__ ((OS_main)) main(void)
2
>
>
> ich kann aber nicht sagen, ob das wirklich gleichwertig ist.

Hm. Ich finde keine Doku zu OS_main. Auf den ersten Versuch macht es bei 
mir genau das selbe wie '__attribute__ ((naked))'. Allerdings umgeht es 
alleine noch nicht, dass main() via rcall gestartet wird. Also wird mit 
OS_main immer noch Stack für eine ungenutzte Rücksprungaddresse 
verwschwendet. Aber es liest sich durchaus eleganter als 'naked'.
#3503929
Lesenswert?

nicht"Gast" schrieb:
> Wenn du diese paar Bytes ganz dringend braucht und es gar keine
> Möglichkeit gibt auf einen größeren Controller zu wechseln, dann lohnt
> sich der Aufwand.
>
> Ansonsten ist es ziemlich nutzlos und reine Verschwendung von Zeit.

Ich hingegen halte es für verplemperte Zeit nach einem 
überdimensionierten Controller zu suchen nur weil ich meine 
Programmiersprache (noch) nicht beherrsche.
#3504109
Lesenswert?

Bei sowas wie einem ATtiny13A mit gerade mal 32 Byte Ram sind zwei Bytes 
ziemlich wertvoll. Auch ging es ja nicht nur um diese zwei Bytes Verlust 
durch rcall, sondern vor allem um all die Register, die nutzlos auf den 
Stack gesichert werden. Da ist schnell alleine durch den main Aufruf 
fast das halbe Ram weg - für nix. Mit zwei Attributen für die main 
Funktion ist das Problem auf nil reduziert. Das zu lernen - da ist 
nichts schief gelaufen.

Schief gelaufen wäre es wenn der Mikrocontroller für die zu bewältigende 
Aufgabe so haarscharf knapp bemessen wäre, dass es an zwei Bytes 
scheitern kann. In dem Fall würde ich Deine Meinung teilen.
#3504413
Lesenswert?

Hihi, das hatte ich auch schon gemacht. Allerdings kostet auch das 2 
Bytes - diesmal aber bloß Flash Rom.

Aber das hat noch andere Effekte: Wenn man tatsächlich absolut gar 
keinen Stack verwendet, kann man ja durchaus auch eine Datenstruktur bis 
ganz zum Ende des Rams legen. Normalerweise werden Daten schon vor dem 
Aufruf von main() initialisiert. Wird jetzt aber nicht der rcall Befehl 
auf main() umgangen, wird diese Initialsierung wieder mit der Adresse 
von main kaputt geschrieben. Aus diesem Grunde ziehe ich die Lösung mit 
_attribute_ ((section(".init8"))) vor.
#3509358
Lesenswert?

Simon K. schrieb:
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Attribute_noreturn.2C_OS_main_und_OS_task

Eine sehr nützliche Seite, von der ich schon viel profitiert habe. 
Vielleicht sollte man sie ein büschn ergänzen um zu erklären, was 
os_main / os_task machen.

Das 'noreturn' für main habe ich aufgegeben, weil das die Ausgabe nicht 
ändert, aber Warnungen generiert, weil in C ja spezifiziert ist dass 
main int zurückliefern soll.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren