assemblygccarm

ARM stack padding generated by compiler


The following function,

#include <string.h>

void  func1(char *s)
{
  char buffer[4];
  strcpy(buffer, s);
}

is compiled,

$ arm-linux-gnueabi-gcc -g -fno-stack-protector  func1.c -c -o func1.o
$ arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Ubuntu 13.2.0-4ubuntu3) 13.2.0

and disassembled:

$ arm-linux-gnueabi-objdump  --disassemble=func1 -S func1.o
void  func1(char *s)
{
    0:   e92d4800        push    {fp, lr}
    4:   e28db004        add     fp, sp, #4
    8:   e24dd010        sub     sp, sp, #16
    c:   e50b0010        str     r0, [fp, #-16]
  char buffer[4];
  strcpy(buffer, s);
    10:   e24b3008        sub     r3, fp, #8
    14:   e51b1010        ldr     r1, [fp, #-16]
    18:   e1a00003        mov     r0, r3
    1c:   ebfffffe        bl      0 <strcpy>
}
    20:   e1a00000        nop                     @ (mov r0, r0)
    24:   e24bd004        sub     sp, fp, #4
    28:   e8bd8800        pop     {fp, pc}

My analysis: just after calling strcpy() (instruction 0x20) the stack has the following contents:

         |---+---+---+---|
fp - 20  |   ?????????   | <- current $sp
         |---+---+---+---|
fp - 16  |   char * s    | <- $r1
         |---+---+---+---|
fp - 12  |   ?????????   |
         |---+---+---+---|
fp - 8   | char buffer[] | <- $r0, $r3
         |---+---+---+---|
fp - 4   |   prev $fp    | <- $sp after push
         |---+---+---+---|
         |      $lr      | <- $fp
         |---+---+---+---|
         |   |   |   |   | <- $sp that had the calling function
         |---+---+---+---|
                 .
                 .
                 .

         ^
         | descending addresses

Questions:


Solution

  • The answer to your first question (why the extra word at the end of the stack) is that the ARM ABI requires the stack to be 8-byte aligned at the start of every function.

    Since the compiler assumes it was aligned at entry to func1, it must add an even number of words before it is allowed to call strcpy. It knows it is wasting that extra word as padding.

    I can only guess at the reason for the space between the variables. I initially thought it was rounding the size of the array up to a multiple of 8, but this isn't correct because the padding is before the array. Maybe it wants it to be an even offset from the frame pointer? That isn't a very satisfying answer either.