関数プロローグでは、-fomit-frame-pointer を使用しても、スタックの現在の位置が呼び出し先の保存済みレジスタに保存されます。
以下の例では、sp+4 が r7 に格納され、エピローグ (LBB0_3) で復元されます (r7+4 -> r4; r4 -> sp)。このため、関数内のどこにでもジャンプでき、関数内の任意の時点でスタックを拡大でき、スタックを台無しにすることはありません。(jump *addr を介して) 関数から飛び出すと、このエピローグをスキップして、スタックを完全に台無しにしてしまいます。
スタックにメモリを動的に割り当てる alloca も使用する短い例:
clang -arch armv7 -fomit-frame-pointer -c -S -O0 -o - stack.c
#include <alloca.h>
int foo(int sz, int jmp) {
char *buf = alloca(sz);
int rval = 0;
if( jmp ) {
rval = 1;
goto done;
}
volatile int s = 2;
rval = s * 5;
done:
return rval;
}
と分解:
_foo:
@ BB#0:
push {r4, r7, lr}
add r7, sp, #4
sub sp, #20
movs r2, #0
movt r2, #0
str r0, [r7, #-8]
str r1, [r7, #-12]
ldr r0, [r7, #-8]
adds r0, #3
bic r0, r0, #3
mov r1, sp
subs r0, r1, r0
mov sp, r0
str r0, [r7, #-16]
str r2, [r7, #-20]
ldr r0, [r7, #-12]
cmp r0, #0
beq LBB0_2
@ BB#1:
movs r0, #1
movt r0, #0
str r0, [r7, #-20]
b LBB0_3
LBB0_2:
movs r0, #2
movt r0, #0
str r0, [r7, #-24]
ldr r0, [r7, #-24]
movs r1, #5
movt r1, #0
muls r0, r1, r0
str r0, [r7, #-20]
LBB0_3:
ldr r0, [r7, #-20]
subs r4, r7, #4
mov sp, r4
pop {r4, r7, pc}