wrong assembly generated for volatile variables in naked function

Bug #1702499 reported by Georgi on 2017-07-05
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain

Bug Description


I'm using the GNU ARM Embedded Toolchain 6-2017-q2-update. I have a naked function (needed for ISR processing), which calls an inline function.

The file is compiled with the following command:
arm-none-eabi-gcc.exe -c -Wa,-aglhn=test.lst -o test.o -Os -pipe -g2 -g -mcpu=cortex-r4f -march=armv7-r -mlittle-endian -mthumb test.c

Here is the file content (test.c):

// ISR macros shrinked to the minimum for the issue
#define ISR_ENTER_M() asm volatile ( "PUSH {R0-R12, LR} \n\t" );
#define ISR_LEAVE_M() asm volatile ( "POP {R0-R12, LR} \n\t" );

inline void test_inline_wait ( int ctr ) __attribute__ ((__always_inline__));
       void test_naked_func ( void ) __attribute__ ((naked));

inline void test_inline_wait ( int ctr )
  // As this is an inline function and the project is compiled with
  // the optimization -Os the counter variable i must be defined as volatile
  // so that the wait loop won't be removed by the compiler.
  volatile int i = ctr;
  while ( i-- > 0 ) ;

void test_naked_func ( void )
  // Do some interrupt handling here

  test_inline_wait ( 100 );


I have actually two problems:
1. If I compile the file with the optimization option -O0 (no optimization), the I get the following error:
"test.c: In function 'test_naked_func':
test.c:21:16: error: cannot allocate stack for variable 'i', naked function.
   volatile int i = ctr;"

2. With the optimization option -Os the file can be compiled without any errors / warnings. The generated assembly is wrong, because it overwrites the stack! Here is the listing for the option -Os:

  26:test.c **** void test_naked_func ( void )
  27:test.c **** {
  25 .loc 1 27 0
  26 .cfi_startproc
  28:test.c **** ISR_ENTER_M();
  30 .loc 1 28 0
  31 .syntax unified
  33 0000 2DE9FF5F PUSH {R0-R12,LR}
  36 .LVL0:
  37 .thumb
  38 .syntax unified
  39 .LBB4:
  40 .LBB5:
  21:test.c **** while ( i-- > 0 ) ;
  41 .loc 1 21 0
  42 0004 6423 movs r3,#100
  43 0006 0193 str r3,[sp,#4]
  44 .L2:
  22:test.c **** }
  45 .loc 1 22 0
  46 0008 019B ldr r3,[sp,#4]
  47 000a 5A1E subs r2,r3,#1
  48 000c 002B cmp r3,#0
  49 000e 0192 str r2,[sp,#4]
  50 0010 FADC bgt .L2
  51 .LVL1:
  52 .LBE5:
  53 .LBE4:
  29:test.c **** // Do some interrupt handling here
  30:test.c ****
  31:test.c **** test_inline_wait ( 100 );
  32:test.c ****
  33:test.c **** ISR_LEAVE_M();
  54 .loc 1 33 0
  55 .syntax unified
  57 0012 BDE8FF5F POP {R0-R12,LR}
  34:test.c **** }

The compiler adds the instruction "str r3,[sp,#4]", which overwrites the current stack. No stack memory is reserved at the beginning of the function. Usually, in a non-naked function the compiler will add the instruction "sub sp, sp, 8" at the beginning of the function and then do the stack access "str r3,[sp,#4]". In this case wrong assembly output is generated.

I newly switched from an older toolchain (5.3 2016q1) to the toolchain 6-2017-q2-update (due to bug #1667509). With the toolchain 5.3 I can compile my test file with both options -Os and -O0. In both cases the instruction "str r3,[sp,#4]" is not generated so that the stack is not corrupted.

Georgi (jimmie.jimmie) wrote :
Georgi (jimmie.jimmie) wrote :

Test file test.c added

Marc Singer (eleventen) wrote :


I have a question for you. Why do you want your ISR function to be naked?

The contemporary ARM cores, and to be fair I only know the Cortex-M cores well enough to be sure, don't need special handling for ISRs. The standard compiler preamble is acceptable. In fact, I think that the core is responsible for register save and restore.

The ARM documentation for exception handling on the Cortex M3 (which I cannot link here as the ARM documentation doesn't provide direct URL access to the documentation) states that

'When the processor takes an exception, unless the exception is a tail-chained or a late-arriving exception, the processor pushes information onto the current stack. This operation is referred to as stacking and the structure of eight data words is referred as the stack frame. The stack frame contains the following information:'

So, the question is this. What core are you using that requires you to manually manage the stack in an exception handler?


To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Bug attachments