Hallo,
ich habe aus Neugier mal meinen RAM-Tester YAART [1] von Pure C auf gcc und libcmini portiert, was mit sehr wenigen Änderungen möglich war. Ein hinterhältiger Bug hat mich aber doch Zeit gekostet. Daher beschreibe ich ihn hier kurz, in der Hoffnung anderen damit zu helfen.
Ich benutze die GEMDOS-Funktion Super, um innerhalb des Codes in den Supervisor-Modus zu schalten und später wieder zurück:
/* switch to supervisor mode so we can manipulate memory */
suret = Super(0);
/* Dinge, die nur im Supervisor-Modus möglich sind */
/* [...] */
/* back to user mode */
Super((void *)suret);
Nun hat der gcc-Optimierer die -- an sich nette -- Eigenschaft, den Stack nicht nach jedem Funktionsaufruf zu korrigieren, sondern die Korrekturen zu sammeln und an späterer Stelle
en bloc durchzuführen. Dummerweise stellt aber bereits
Super((void *)suret); den Stack zurück. gcc hat nun in meinem Fall die Stackkorrekturen für die Funktionsaufrufe, die im Supervisor-Modus ausgeführt wurden, erst danach gemacht. Dadurch wird der Stack beschädigt und spätestens beim nächsten
return fliegt einem das ganze mit Bömbchen um die Ohren.
Glücklicherweise gibt es eine Lösung, ohne dass man diese sinnvolle Optimierung ganz abschalten muss. Man deklariert die Funktion, in der die Super-Aufrufe sind, als
void foobar(void) __attribute__ ((optimize ("no-defer-pop")));
und aktiviert somit nur lokal für diese Funktion die sofortige Stackkorrektur nach jedem Funktionsaufruf.
Noch besser wäre es natürlich, könnte man gcc mitteilen, dass Super eine Funktion ist, die den Stack modifiziert und deshalb alle Stackkorrekturen nur bis zum nächsten Aufruf von Super gesammelt werden können. Eine Art Barriere also. Weiß jemand, ob das geht?
[1]
http://forum.atari-home.de/index.php?topic=13002.msg208583#msg208583