为什么编译器会保留一点堆栈空间而不是整个数组大小?

Rio*_*lku 1 assembly x86-64 red-zone

以下代码

int main() {
  int arr[120];
  return arr[0];
}
Run Code Online (Sandbox Code Playgroud)

编译成这样:

  sub     rsp, 360
  mov     eax, DWORD PTR [rsp-480]
  add     rsp, 360
  ret
Run Code Online (Sandbox Code Playgroud)

知道整数是 4 个字节,数组的大小为 120,数组应该占用 480 个字节,但从 ESP 中只减去了 360 个字节......这是为什么?

Tho*_*ger 5

在函数使用的堆栈区域下方,有一个128 字节的红色区域,保留供程序使用。由于不main调用其他函数,因此无需将堆栈指针移动超出所需的范围,尽管在这种情况下无关紧要。它仅减去足够的rsp以确保阵列受红色区域保护。

您可以通过添加函数调用来查看差异 main

int test() {
  int arr[120];
  return arr[0]+arr[119];
}

int main() {
  int arr[120];
  test();
  return arr[0]+arr[119];
}
Run Code Online (Sandbox Code Playgroud)

这给出了

test:
  push rbp
  mov rbp, rsp
  sub rsp, 360
  mov edx, DWORD PTR [rbp-480]
  mov eax, DWORD PTR [rbp-4]
  add eax, edx
  leave
  ret
main:
  push rbp
  mov rbp, rsp
  sub rsp, 480
  mov eax, 0
  call test
  mov edx, DWORD PTR [rbp-480]
  mov eax, DWORD PTR [rbp-4]
  add eax, edx
  leave
  ret
Run Code Online (Sandbox Code Playgroud)

您可以看到main函数减去 480,因为它需要数组位于其堆栈空间中,但 test 不需要,因为它不调用任何函数。

数组元素的额外使用不会显着改变输出,但添加它是为了明确表示它不会假装这些元素不存在。

  • 您可以使用内联 asm(或者可能是 `volatile`)来获取叶函数中的实际数组访问,而不必像您在这里所做的那样禁用优化。但是访问 `arr[119]` 以显示顶部的位置是个好主意。使用 `-fno-omit-frame-pointer` 作为 `-O0` 的一部分使得一切都与 RBP 相关,但这与 OP 的代码不同。 (2认同)