https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69979
Bug ID: 69979 Summary: ARM naked function attribute not handling structs bigger than 32 bits correctly Product: gcc Version: 6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: andre.simoesdiasvieira at arm dot com Target Milestone: --- As reported by Cory in https://bugs.launchpad.net/gcc-arm-embedded/+bug/1549542 It seems the naked function attribute for ARM is generating code for struct parameters being passed in registers. This code stores these structs being passed as registers on the stack, using 'r3' as a scratch register. Apart from being suboptimal, this writes to 'r3' even though 'r3' might be used to hold a parameter! For instance with the following C code: struct test { int a; int b; }; int foo (struct test t, int a, int b) { __asm ("mov r0, r3\n\t" "bx lr"); } when compiled with $arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -S will yield the following assembly: foo: @ Naked Function: prologue and epilogue provided by programmer. @ args = 0, pretend = 0, frame = 8 @ frame_needed = 1, uses_anonymous_args = 0 mov r3, r7 stm r3, {r0, r1} .syntax unified @ 9 "tnaked.c" 1 mov r0, r3 bx lr @ 0 "" 2 .syntax unified nop mov r0, r3 As you see 'r3' will have been rewritten with the frame pointer before being moved to 'r0' for the return. Also the last 'mov r0, r3' after the 'nop' looks a bit odd! Something equally weird happens when returning such a struct: struct test bar (int a, int b, int c) { __asm ("stmia r0, {r2, r3}\n\t" "bx lr"); } One would naturally expect to be storing 'b' and 'c' into '[r0]', the place where the caller expects the return value to be written to. However the following assembly is generated, which overwrites r3 (which should contain argument 'c'): bar: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. mov r3, r0 @ 16 "tnaked.c" 1 stmia r0, {r2, r3} bx lr @ 0 "" 2 .thumb mov r0, r3 bx lr Again with the unexpected epilogue code creeping in. I have observed this behavior for various ARM targets dating back to gcc 4.8 (haven't tried earlier than that).