I'm currently in the process of adapting the ST Pole Position code so that it works with GCC 7.1. I've now managed to get it to compile, but upon running it, the executable bombed out with what I think are 8 bombs - I can't see them for long enough to count them! 8 bombs appears to translate to a privilege violation, so I started looking at the area of my code that moves into supervisor mode.

It appears that the call to Super() (to move into supervisor mode) executes correctly, but the executable then bombs out on executing the inline assembly to disable all interrupts. It's as if the machine hasn't entered supervisor mode at all.

In order to try and get to the bottom of the issue, I've created a minimal test case based upon the ctest.c in the bigbrownbuild repo:

// force GCC to keep functions that look like they might be dead-stripped due to non-use#define USED __attribute__((used))

int main(int argc, char ** argv){ Super(0);

__asm__ __volatile__ ( "move.w #0x2700,%%sr;" : : : "cc" );

while (1==1) {}}

What I'd expect this code to do is enter supervisor mode, disable interrupts and then hang. Instead, it bombs out on the inline assembly with what appears to be 8 bombs. This code (or at least code very similar to it) works fine under Vincent's GCC. I'm wondering if I'm doing something wrong that Vincent's compiler somehow allows but GCC 7.1 is less forgiving of.

I'd be extremely grateful if somebody could help me get a better understanding of what's going wrong here! Thanks in advance for any responses.

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.

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!

Many thanks Doug for the usual comprehensive and swift reply! I've switched to using Supexec as suggested and that seems to do the trick.

I'm really impressed with the performance improvements in this version - the -flto support in particular makes a big difference to runtime performance! Thanks to you and everybody else involved for making this GCC 7.1 release a reality.

dml wrote: (because I normally provide a new SSP stack when using Super())

That's usually a bad idea. If you compile your code with -fomit-frame-pointer, then local variables that are not in registers are accessed through xx(SP). gcc will not recognize that you changed the SP, and therefore access the wrong memory when trying to load/store them.

dml wrote: Supexec(&SYS_SuperStart, 0,0,0,0,0);

That code is also bogus. Taking the address of a function with an extra address operator is undefined. The Supexec() macro in mintlib headers only takes 1 parameter, so that code won't even compile. Beside that, passing extra parameters to the function called by Supexec only works in MiNT.

chicane wrote:I'd be extremely grateful if somebody could help me get a better understanding of what's going wrong here! Thanks in advance for any responses.

The easiest way, if you have a small example like yours that can reproduce the bug, is to compile it with -S and look at the generated assembler code.

ThorstenOtto wrote:That's usually a bad idea. If you compile your code with -fomit-frame-pointer, then local variables that are not in registers are accessed through xx(SP). gcc will not recognize that you changed the SP, and therefore access the wrong memory when trying to load/store them.

That's what I was explaining above.

dml wrote:That code is also bogus. Taking the address of a function with an extra address operator is undefined. The Supexec() macro in mintlib headers only takes 1 parameter, so that code won't even compile. Beside that, passing extra parameters to the function called by Supexec only works in MiNT.

Depends on which header defines the macro. mint/sysbind.h defines it this way, and accepts long, not a function pointer.