ARM编译器栈填充:栈指针指向内容与变量间隙技术问询
ARM栈相关问题分析与解答
原函数代码
#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
问题解答
- ARM满递减栈模式下$sp指向的内容
在ARM满递减(Full Descending, FD)栈模式中,$sp指向当前栈帧里最后一个被分配、已标记为占用的栈空间位置(即栈图中的fp - 20处)。这个空间属于当前函数的栈帧范围,但属于未初始化的空白区域,没有存放有效业务数据;按照ARM调用约定,被调用函数不会主动使用该位置,只会使用自身分配的栈空间或约定的栈区域。
满递减栈的核心行为是:压栈时先将$sp递减,再写入数据;出栈时先读取$sp指向的数据,再递增$sp,因此$sp始终指向栈中已占用的最低地址(最高偏移)位置。
- 局部变量间未使用空间的原因
这是栈对齐规则导致的填充空间。ARM EABI(应用二进制接口)要求栈指针必须保持8字节或16字节的对齐(此处GCC遵循标准ARM EABI的8字节对齐要求),未对齐的内存访问可能触发硬件异常,或导致处理器性能下降,因此编译器会自动填充空隙以满足对齐要求。
在当前函数中:
- 压入
fp和lr占用8字节,此时栈处于对齐状态; - 执行
sub sp, sp, #16分配16字节局部空间,维持栈的对齐; - 局部变量
buffer[4]和参数s总共仅占用8字节,剩余的4字节(fp - 12处)就是为满足栈对齐要求而填充的空隙。
内容的提问来源于stack exchange,提问作者Isidro Arias
相关产品推荐
相关产品推荐

