为什么在分配没有后续函数调用的大数组时,GCC 会向堆栈指针减去错误的值? [英] Why does GCC subtract the wrong value to the stack pointer when allocating a big array with no subsequent function calls?

查看:24
本文介绍了为什么在分配没有后续函数调用的大数组时,GCC 会向堆栈指针减去错误的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

真是奇怪的 gcc 怪癖.看看这个:

Really bizarre gcc quirk. Check this out:

main() { int a[100]; a[0]=1; }

产生这个程序集:

   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 18 01 00 00    sub    $0x118,%rsp
   b:   c7 85 70 fe ff ff 01    movl   $0x1,-0x190(%rbp)
  12:   00 00 00 
  15:   c9                      leaveq 
  16:   c3                      retq

堆栈的顶部显然是 400,因为它是一个 100 * 4 的数组.因此,当它写入第一个条目时,它会执行 rbp - 400(b"行).好的.但是为什么它从堆栈(第'4'行)指针中减去280?那不是指向数组的中间吗?

The top of the stack is clearly 400, since its a 100 * 4 array. So when it writes to the first entry, it does rbp - 400 (line 'b'). Good. But why does it subtract 280 from the stack (line '4') pointer? Doesn't that point to the middle of the array?

如果我们之后添加一个函数调用,gcc 会做正确的事:

If we add a function call afterward, gcc does the right thing:

b() {}
main() { int a[100]; a[0]=1; b(); }

产生这个程序集:

0000000000000000 <b>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   c9                      leaveq 
   5:   c3                      retq   

0000000000000006 <main>:
   6:   55                      push   %rbp
   7:   48 89 e5                mov    %rsp,%rbp
   a:   48 81 ec 90 01 00 00    sub    $0x190,%rsp
  11:   c7 85 70 fe ff ff 01    movl   $0x1,-0x190(%rbp)
  18:   00 00 00 
  1b:   b8 00 00 00 00          mov    $0x0,%eax
  20:   e8 00 00 00 00          callq  25 <main+0x1f>
  25:   c9                      leaveq 
  26:   c3                      retq 

在这里,它正确地减去了 400(行 'a').

Here, it properly subtracts 400 (line 'a').

为什么添加函数调用时会发生变化?gcc 只是懒惰,因为没关系而没有做对吗?发生了什么?显然,这只发生在为 x86_64 编译时,而不是为普通 x86 编译时.这与 x86_64 的redzone"有什么奇怪的关系吗?究竟发生了什么?

Why the change when you add a function call? Is gcc just lazy, and doesn't do it right because it doesn't matter? What's happening? Evidently this only happens when compiling for x86_64, but not for plain x86. Does this have something odd to do with x86_64's "redzone"? What's happening precisely?

推荐答案

你猜对了.这是一个红色区域".红色区域是从 rsp-128 到 rsp 的空间,它可能被函数用于局部变量和临时存储.该空间不受中断和异常处理程序的影响.很明显,红色区域是被函数调用破坏的,所以如果调用任何函数,红色区域中就不能有局部变量.

Your guess is correct. It is a "red zone". The red zone is the space from rsp-128 to rsp, which may be used by a function for local variables and for temporary storage. This space is untouched by interrupt and exception handlers. Obviously, the red zone is destroyed by function calls, so if any function is called, no local variable can be in the red zone.

红色区域只能用于 64 位 Linux、BSD 和 Mac.它在内核代码中不可用.

The red zone can only be used in 64 bit Linux, BSD and Mac. It is not available in kernel code.

它可用于优化空间,因为在红色区域中,您可以使用短指令引用最多 512 字节的局部变量,仅基于 rsp 和 ebp.没有红色区域,只有 384 字节可用.所有超出此限制的局部变量都可以使用更长的代码或额外的寄存器来访问.

It may be used to optimize for space, since with the red zone you can reference up to 512 bytes of local variables with short instructions, based on only rsp and ebp. Without the red zone only 384 bytes are available. All local variables outside of this limit are accessed with longer code or with additional registers.

对于您的示例,不需要使用红色区域,但 gcc 更喜欢将它用于所有叶子"功能.以这种方式实现编译器更容易.

For your example, using the red zone is not necessary, but gcc prefers to use it for all "leaf" functions. It is just easier to implement compiler this way.

这篇关于为什么在分配没有后续函数调用的大数组时,GCC 会向堆栈指针减去错误的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆