-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
gcc7 ARM M4 compiler change breaks nlr_push() and nlr_push_tail() #3526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I believe I've fixed this in CircuitPython by adding some "clobbered register" info to the
See adafruit#506 and adafruit#500. |
I've tried your workarounds (both using I'm running into this issue on x86_64 with GCC 5.4.0. Please help :-) |
I'm not sure what to suggest for gcc 5.4.0. We haven't done deveopment with our fork on gcc 5 or below. We were fine with gcc 6.3.1 and encountered the problem with gcc 7. If you could at least upgrade to gcc 6 the problem may go away. |
Hi dhalbert, LoBo's tests seem to lead similar results: It might indeed be a good idea that I upgrade to 6.x. Thanks! |
I just tried with |
To get an idea about a proper fix in assembly code you could check out the disassembly of setjmp/longjmp as it is basically the same functionally |
Thanks stinos, this sounds like a reasonable idea. I'll try that and come back with what I find :-) |
I finally found it! It was SSP, not PIE. I'm not sure if that's the right solution for upstream though? |
@Cheaterman could you open a different issue for this? Your problems sound different from the specific ARM M4 issues I reported in the original issue. |
Yes, I apologize for hijacking your issue @dhalbert. Opening a new issue right now! |
My guess is that it's a limitation of the compiler/linker, that you can't use LTO and also inline asm. Does the problem go away if you write nlr_push in pure assembler as a .s (or .S) file (using exactly the same code as in nlrthumb.c)?
According to the gcc docs this is not allowed, in naked functions you must only have basic asm statements, which means you can't use a clobbered register list; see https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html |
Thanks for your comments. Extended asm is not allowed in naked functions, so says the doc, yet it does work, and even fixes the problem. (E pur si muove.) At this point I consider this a workaround. Because the M0 output does not have the problem, and the M4 does, I wonder if there's an issue with the gcc M4 architecture description, and we are hitting an edge case. There has been some discussion of extended vs basic asm and clobbers on the gcc list, for instance: https://www.mail-archive.com/gcc@gcc.gnu.org/msg78703.html. But the "naked" attribute has not been part of the discussion, as far as I can see, except that it's an exception. I'll try the .S file thing at some point, but I think I will bring up the issue on the gcc mailing list as well to clarify the issue. I have tried coming up with a small test case to file a gcc bug report, but didn't succeed (yet). |
I think this has been fixed by 5591bd2 |
Uh oh!
There was an error while loading. Please reload this page.
We recently starting using the gcc-arm-none-eabi-7-2017-q4-major toolchain, which uses gcc 7.2.1. We also use
-flto
. On M0+, it works OK, but on M4, I found an issue having to do withmp_call_function_1_protected()
,nlr_push()
andnlr_push_tail()
. The assembly code emitted is below. Note thatmp_call_function_1_protected()
savesr0
inr3
while it callsnlr_push()
.nlr_push()
is OK, butnlr_push_tail()
thinks that it's OK to user3
as a scratch register, and smashes it.The ARM calling conventions are that
r0-r3
are for arg passing, andr4
and up are for locals.In the M0 assembly code, and in non-LTO compilations,
r0
gets saved inr4
, which is safer.I'm not sure if this is an actual compiler bug or simply a pathological case due to asm-jumping from a
naked
function into a regular one (nlr_push_tail
), and the optimizer or register allocator don't notice.If I put in a regular call to something else before
nlr_push
, then the problem goes away (E.g., when I put in amp_printf()
!).I'm writing this down as a warning to others for now. I have to think of some way to fix this. I was thinking about using local register variables and rewriting
nlr_push
as C code that stores the registers intonlr_buf
. Or I can just put in a dummy call as mentioned above to force safer code to be generated. Comments welcome.The text was updated successfully, but these errors were encountered: