这是我用
gcc
编译的C代码 -
#include <stdio.h>
#include <stdlib.h>
int sum(int arr[20]) {
int s = 0;
for (int i = 0; i < 20; i++)
s += arr[i];
return s;
}
int main(int argc, char **argv) {
int arr[20] = {4, 5, 2, 12, 0, -23};
printf("%d\n", sum(arr));
return 0;
}
它生成的程序集 -
sum:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov DWORD PTR [rbp-4], 0
mov DWORD PTR [rbp-8], 0
jmp .L2
.L3:
mov eax, DWORD PTR [rbp-8]
cdqe
lea rdx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rax, rdx
mov eax, DWORD PTR [rax]
add DWORD PTR [rbp-4], eax
add DWORD PTR [rbp-8], 1
.L2:
cmp DWORD PTR [rbp-8], 19
jle .L3
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
.LC0:
.string "%d\n"
main:
push rbp
mov rbp, rsp
sub rsp, 96
mov DWORD PTR [rbp-84], edi
mov QWORD PTR [rbp-96], rsi
pxor xmm0, xmm0
movaps XMMWORD PTR [rbp-80], xmm0
movaps XMMWORD PTR [rbp-64], xmm0
movaps XMMWORD PTR [rbp-48], xmm0
movaps XMMWORD PTR [rbp-32], xmm0
movaps XMMWORD PTR [rbp-16], xmm0
mov DWORD PTR [rbp-80], 4
mov DWORD PTR [rbp-76], 5
mov DWORD PTR [rbp-72], 2
mov DWORD PTR [rbp-68], 12
mov DWORD PTR [rbp-60], -23
lea rax, [rbp-80]
mov rdi, rax
call sum
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
我主要关心的是
sum
函数。当我们压入旧的基指针值并将堆栈指针的当前值移入基指针后,rbp
标记了堆栈的顶部。因此,从中减去的任何数量都意味着堆栈中存在未分配的空间。为什么 gcc
在未分配的空间中写入?为什么它不像 main
函数那样首先通过从堆栈指针中减去来腾出空间?
我希望所有函数首先为其局部变量腾出空间。但在这种情况下却没有
因为gcc使用基指针(rbp)直接访问局部变量,而不需要调整堆栈指针(rsp)。这种方法通常称为“帧指针”方法。它通常用于叶函数(不调用其他函数的函数)或小函数中,以减少开销并提高性能。
优化:GCC对sum函数进行了优化,对于小的局部变量直接使用栈帧,避免了不必要的栈指针调整。
空间分配:在需要更多空间的函数中(如 main),GCC 显式调整堆栈指针以分配足够的空间。