[Bug target/69979] New: ARM naked function attribute not handling structs bigger than 32 bits correctly

andre.simoesdiasvieira at arm dot com gcc-bugzilla@gcc.gnu.org
Fri Feb 26 13:20:00 GMT 2016


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).


More information about the Gcc-bugs mailing list