Hi!
While I can't say conclusively what's happening here (because I normally provide a new SSP stack when using Super()), I can say that I had similar problems with this function - and the problems have much to do with the method of changing mode versus the compiler's knowledge of what just happened under its feet. Particularly with changes to the stack, what was on it before the switch, access to it after the switch - but potentially other state as well.
Some other things to be wary of:
1) The newer compilers are a bit more aggressive at high-mid level optimisation and any undefined behaviour (which may include stuff going on inside Super) is more likely to cause invalid code to be produced and actual crashes.
2) The macros used to implement things like Super() via assembly code may not be properly constrained, causing trashed registers etc. which the compiler isn't aware of (mint headers need inspection to check this properly).
In any case you can almost certainly solve the problem by using Supexec(_MyEntrypoint) instead because the context save/restore becomes part of the trap itself, and not left to the compiler to guess at (which is probably making incorrect assumptions about machine state across the switch). This works without the same risks. You just need to be aware that any args need passed via globals or via the trap, since the stack will be swapped and local variables/args disappear (or at least go out of reach) as a result.
I use something like the following pattern:
Code: Select all
#include <mint/sysbind.h>
void SYS_SuperStart()
{
// main program to run in supervisor mode
}
int main(int argc, char **argv)
{
Supexec(&SYS_SuperStart, 0,0,0,0,0);
return 0;
}
If you want to replace and align the supervisor stack as part of the process you can add an extra level in-between to do this. e.g.
Code: Select all
#define S_SUPER_SSP(_sz_) \
static const int ssp_size = _sz_>>2; \
u32 s_new_ssp[ssp_size]; \
u32 s_old_ssp; \
u32 s_old_usp;
Code: Select all
S_SUPER_SSP(8192)
void SYS_SuperStart() \
{ \
__asm__ __volatile__ \
( \
" \
move.l %0,%%a0; \
move.l %%a0,%%d0; \
subq.l #4,%%d0; \
and.w #-16,%%d0; \
move.l %%d0,%%a0; \
move.l %%sp,-(%%a0); \
move.l %%usp,%%a1; \
move.l %%a1,-(%%a0); \
move.l %%a0,%%sp; \
movem.l %%d1-%%d7/%%a2-%%a6,-(%%sp); \
jsr (%2); \
movem.l (%%sp)+,%%d1-%%d7/%%a2-%%a6; \
movem.l %%d1-%%d7/%%a2-%%a6,-(%%sp); \
jsr (%1); \
movem.l (%%sp)+,%%d1-%%d7/%%a2-%%a6; \
movem.l %%d1-%%d7/%%a2-%%a6,-(%%sp); \
jsr (%3); \
movem.l (%%sp)+,%%d1-%%d7/%%a2-%%a6; \
move.l (%%sp)+,%%a0; \
move.l %%a0,%%usp; \
move.l (%%sp)+,%%sp; \
" \
: \
: "p"(&s_new_ssp[ssp_size-16]), "a"(&SYS_EntryPoint), "a"(&SYS_EntryPointPre), "a"(&SYS_EntryPointPost) \
: "%%d0", "%%a0", "%%a1", "cc" \
); \
} \
This is a fragment of AGT's startup sequence - it will replace the stack with C-array 's_new_ssp', align it to 16 bytes, then call SYS_EntryPointPre(), SYS_EntryPoint(), SYS_EntryPointPost() in that order. It also saves/restores SSP/USP properly for exit.
Pay extra attention to the MiNT includes used to specify the Super/Supexec macros and the number of args they expect - the definitions of these are not all the same!