This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ARM-CGT: Manual 8-byte stack alignment in assembly for AAPCS compliance

Part Number: ARM-CGT

Hi,

I'm using tiarmclang v3.2 and have a custom interrupt handler for C functions which is written in assembly. I can't use interrupt function attribute as this does not preserve FPU registers, which I need. I know how to do this but I don't understand how to ensure the stack is 8-byte aligned before executing the C ISR. From the tiarmclang manual interrupt attribute section:

> "The tiarmclang compiler will re-align the stack pointer to an 8-byte boundary on entry into a function marked with the interrupt attribute because the Arm Procedure Call Standard (AAPCS) requires this alignment for all public interfaces."

 

In that same section they demonstrate an example of the 8-byte stack alignment does:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
> tiarmclang -mcpu=cortex-r4 -S interrupt_function_attr.c
> cat interrupt_function_attr.s
...
int2:
.fnstart
@ %bb.0: @ %entry
push {r0, r1, r2, r3, r10, r11, r12, lr}
add r11, sp, #20
bfc sp, #0, #3
bl do_something2
sub sp, r11, #20
pop {r0, r1, r2, r3, r10, r11, r12, lr}
subs pc, lr, #4
...
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

The problem is, the text explaining what's going on doesn't match the code:

> "When compiled with the -mcpu=cortex-r4 option, the compiler-generated assembly snippet shows general-purpose registers being preserved during the function’s entry and exit code, the re-alignment of the stack pointer via the “sub sp, sp, #8” and “bfc sp, #0, #3” instructions, and the addition of the “subs pc, lr, #4” instruction to effect the exception return."

(emphasis mine)

There is no `sub sp, sp, #8` instruction shown. Could someone clarify:

1. Why `r10` get's pushed to the stack when it's a) not being used, and b) the C Exception handler Calling Convention section only says `R0-R3, R-12, LR` need to be preserved? I'm guessing because the r1 reg is being used and we want to always push an even number of registers to the stack to maintain 8-byte alignment if we already have it?

2. How the add and bfc instructions are keeping the stack 8-byte aligned

3. How my general purpose interrupt handler code below can be modified to ensure the stack is aligned to 8 bytes before calling an ISR. This is inline assembly that I wrap around my ISRs in C instead of using the interrupt attribute. I already have the code to call the function and handle register stacking and exception return so I've omitted that.

Fullscreen
1
2
3
4
5
6
7
8
push {r0, r1, r2, r3, r10, r11, r12, lr}
vmrs ip, fpexc
stmfd sp!, {ip}
vmrs ip, fpscr
stmfd sp!, {ip}
vpush {d0-d7}
<omitting code to call the function here, I have this already>
<omitting code to handle register unstacking and exception return, I have this>
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Thank you!

  • Hi Daniel,

    I can respond to a part of your inquiry ...

    You are correct that the documentation is not accurate on how the re-alignment of the stack pointer is being accomplished inside the interrupt function. I believe the documentation should be adjusted to read as follows:

    the re-alignment of the stack pointer via a forced adjustment to the stack and a “bfc sp, #0, #3” instructions. In the example shown, the stack is adjusted prior to the "bfc sp,#0,#3" instruction by pushing an extra 2 registers (r10 and r11) onto the stack. In other cases, the compiler may use a "sub sp,sp,#8" instruction to force an adjustment to the stack prior to the "bfc sp,#0,#3" instruction.

    Regarding question #3, I suspect you need to insert a "bfc sp,#0,#3" instruction (or a functionally equivalent code sequence) prior to the push of the fpexc instruction in your code.

    Hope this helps.

    Regards,

    Todd Snider

    TI Arm Clang Compiler Tools Team