Forum: ARM programming with GCC/GNU tools Control ARM prologue/epilogue assembly code emission

von Albert H. (Company: RFIDspan) (albert_hong)

Rate this post
0 useful
not useful

Is there anyway to control how  ARM GCC to emit assembly for the 
prologue/epilogue?  I am using Atmel SAM4LS2A and it seems like the push 
instruction does not work with the chip (The chip does not save 
correctly the registers onto the stack). Instead of emitting the push 
instruction at the prologue, I am wondering if I can control the GCC to 
emit STMDB instruction which is working (I tested).


von Kindergärtner (Guest)

Rate this post
0 useful
not useful
The Cortex-M4F (ARMv7M) does not have an explicit PUSH instruction, but 
only "STM". Verify that you call the compiler correctly for that core 
(flags -mcpu=cortex=M4 -mthumb). Paste the disassembly, step through the 
instructions with a debugger and explain why you believe that the 
registers are not saved.

von Albert H. (Company: RFIDspan) (albert_hong)

Attached files:

Rate this post
0 useful
not useful

Thanks for the reply.

I do use "flags -mcpu=cortex=M4 -mthumb" and the compiler does generate 
the push instruction:

Please see below:

arm-none-eabi-gcc.exe"  -mthumb -D__SAM4LS2A__ -DARM_MATH_CM4=true 
-DBOARD=USER_BOARD -Dprintf=iprintf -D__ATSAM4LS2A__  -I"../src" 
-I"../src/ASF/common/boards" -I"../src/ASF/common/boards/user_board" 
-I"../src/ASF/common/utils" -I"../src/ASF/sam/utils" 
-I"../src/ASF/thirdparty/CMSIS/Lib/GCC" -I"../src/config" -I"C:\Program 
Files (x86)\Atmel\Atmel Toolchain\ARM 
-I"C:\Program Files (x86)\Atmel\Atmel Toolchain\ARM 
ude"  -I"C:\Program Files (x86)\Atmel\Atmel Toolchain\ARM 
EL"  -I"C:\Program Files (x86)\Atmel\Atmel Toolchain\ARM 
EL\sam4l\include"  -I"../src/ASF/sam/drivers/bpm" 
-I"../src/ASF/sam/drivers/flashcalw" -I"../src/ASF/sam/drivers/gpio" 
-I"../src/ASF/common/services/ioport"  -O1 -fdata-sections 
-ffunction-sections -mlong-calls -g3 -Wall -mcpu=cortex-m4 -c -pipe 
-fno-strict-aliasing -Wall -Wstrict-prototypes -Wmissing-prototypes 
-Werror-implicit-function-declaration -Wpointer-arith -std=gnu99 
-ffunction-sections -fdata-sections -Wchar-subscripts -Wcomment 
-Wformat=2 -Wimplicit-int -Wmain -Wparentheses -Wsequence-point 
-Wreturn-type -Wswitch -Wtrigraphs -Wunused -Wuninitialized 
-Wunknown-pragmas -Wfloat-equal -Wundef -Wshadow -Wbad-function-cast 
-Wwrite-strings -Wsign-compare -Waggregate-return 
-Wmissing-declarations -Wformat -Wmissing-format-attribute 
-Wno-deprecated-declarations -Wpacked -Wredundant-decls -Wnested-externs 
-Wlong-long -Wunreachable-code -Wcast-align --param 
max-inline-insns-single=500 -D__ATSAM4LS2A__ -MD -MP -MF 
-MT"src/ASF/common/utils/interrupt/interrupt_sam_nvic.o"   -o 
    Finished building: 

Please see the attached screen capture for the problem (I'm using Atmel 
studio 6.1)

Thanks for your help.

von Kindergärtner (Guest)

Rate this post
0 useful
not useful
Sorry, i don't have MS Office. Please paste as plain text (the 
disassembled file). There is no PUSH instruction, the "PUSH" assembler 
mnemonic is just an alias for STMDB. The GCC disassembler ("objdump") 
should always print "STMDB", not "PUSH", though.

von Albert H. (Company: RFIDspan) (albert_hong)

Rate this post
0 useful
not useful
The following is the source code. I purposely put an
  asm("STMDB   sp!, {r4, r5, lr}"); to test if the STMDB instruction 
works for the chip, which it does.

int main (void)
   asm ("b .");

   asm("STMDB   sp!, {r4, r5, lr}");
   //asm("push  {r4, r5, r6, lr}");
   //asm("push  {r4, r5, lr}");
   //asm("push {lr}");
   //asm("push {lr}");
   //asm("push {r5, lr}");
   CR_Reg = __get_CONTROL ();
   MSP_Reg = __get_MSP();
   PRIMask_Reg = __get_PRIMASK();


  //asm("STMDB   sp!, {a1-a2, v1-fp, lr}");
  //asm ("b OsSchedule");

      TASK_CREATE(&MainTask, main_tsk, (void *)Main_Stk, 2 * 1024, 3, 0, 
OS_DEFAULT_MODES, "maintask");
  //asm("LDMIA   sp!, {v1-fp, lr}");
  //asm("bx    lr");

  // YYY++;

  // Insert application code here, after the board has been initialized.

The following is the assembly code (by objdump), as you can see the 
compiler does generate push instruction which is different from the 
STMDB instruction.

00000b88 <main>:
 b88:   b530            push    {r4, r5, lr}
 b8a:   b085            sub     sp, #20
 b8c:   e7fe            b.n     b8c <main+0x4>
 b8e:   e92d 4030       stmdb   sp!, {r4, r5, lr}
 b92:   f640 4325       movw    r3, #3109       ; 0xc25
 b96:   f2c0 0300       movt    r3, #0
 b9a:   4798            blx     r3
 b9c:   f04f 0000       mov.w   r0, #0
 ba0:   f240 21e5       movw    r1, #741        ; 0x2e5
 ba4:   f2c0 0100       movt    r1, #0
 ba8:   4788            blx     r1
 baa:   f3ef 8214       mrs     r2, CONTROL
 bae:   f640 10b0       movw    r0, #2480       ; 0x9b0
 bb2:   f2c2 0000       movt    r0, #8192       ; 0x2000
 bb6:   6002            str     r2, [r0, #0]
 bb8:   f3ef 8408       mrs     r4, MSP
 bbc:   f640 2544       movw    r5, #2628       ; 0xa44
 bc0:   f2c2 0500       movt    r5, #8192       ; 0x2000
 bc4:   602c            str     r4, [r5, #0]
 bc6:   f3ef 8110       mrs     r1, PRIMASK
 bca:   f640 13b8       movw    r3, #2488       ; 0x9b8
 bce:   f2c2 0300       movt    r3, #8192       ; 0x2000
 bd2:   6019            str     r1, [r3, #0]
 bd4:   b672            cpsid   i
 bd6:   f04f 0203       mov.w   r2, #3
 bda:   9200            str     r2, [sp, #0]
 bdc:   f04f 0400       mov.w   r4, #0
 be0:   9401            str     r4, [sp, #4]
 be2:   9402            str     r4, [sp, #8]
 be4:   f640 704c       movw    r0, #3916       ; 0xf4c
 be8:   f2c0 0000       movt    r0, #0
 bec:   9003            str     r0, [sp, #12]
 bee:   f640 10bc       movw    r0, #2492       ; 0x9bc
 bf2:   f2c2 0000       movt    r0, #8192       ; 0x2000
 bf6:   f640 3165       movw    r1, #2917       ; 0xb65
 bfa:   f2c0 0100       movt    r1, #0
 bfe:   f640 2248       movw    r2, #2632       ; 0xa48
 c02:   f2c2 0200       movt    r2, #8192       ; 0x2000
 c06:   f44f 6300       mov.w   r3, #2048       ; 0x800
 c0a:   f640 058d       movw    r5, #2189       ; 0x88d
 c0e:   f2c0 0500       movt    r5, #0
 c12:   47a8            blx     r5
 c14:   f240 7101       movw    r1, #1793       ; 0x701
 c18:   f2c0 0100       movt    r1, #0
 c1c:   4788            blx     r1
 c1e:   4620            mov     r0, r4
 c20:   b005            add     sp, #20
 c22:   bd30            pop     {r4, r5, pc}

von Albert H. (Company: RFIDspan) (albert_hong)

Attached files:

Rate this post
0 useful
not useful
Please find the attached file for screen captures in PDF format.

von Kindergärtner (Guest)

Rate this post
0 useful
not useful
Oh you were right, the PUSH instruction has a specific encoding for <=9 
registers. Indeed, r5 doesn't seem to be pushed at all, resulting lr 
ending up in the wrong place. Have you tried this with an other 
mikrocontroller? Maybe that one is defect... This should definitely work 
(it does on my STM32F4 which is a Cortex-M4, too - i.e. has exactly the 
same core). I don't think GCC can be stopped from generating the "PUSH" 
instruction because it should work.


Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]

Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.