编译器生成的ARM堆栈填充

问题描述 投票:0回答:1

以下功能,

#include <string.h>

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

已编译,

$ 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

拆解:

$ 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}

我的分析:调用

strcpy()
(指令
0x20
)后,堆栈有以下内容:

         |---+---+---+---|
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

问题:

  • $sp
    指的是什么内容?由于 ARM 使用完整降序堆栈,因此该元素被标记为已占用,并且被调用的函数将不会使用该空间。
  • 为什么两个局部变量之间有未使用的空间?
assembly gcc arm
1个回答
0
投票

第一个问题(为什么在堆栈末尾有额外的字)的答案是 ARM ABI 要求堆栈在每个函数的开始处都是 8 字节对齐。

由于编译器假设它在

func1
的入口处对齐,因此在允许调用
strcpy
之前,它必须添加偶数个单词。 它知道它浪费了额外的单词作为填充。

我只能猜测变量之间存在空格的原因。 我最初认为它将数组的大小四舍五入为 8 的倍数,但这是不正确的,因为填充位于数组之前。 也许它希望它与帧指针的偏移量相等? 这也不是一个非常令人满意的答案。

© www.soinside.com 2019 - 2024. All rights reserved.