海湾合作委员会的说法寄存器溢出X86-64上 [英] gcc argument register spilling on x86-64

查看:213
本文介绍了海湾合作委员会的说法寄存器溢出X86-64上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在做一些与x86-64的装配试验。说完这个编译虚拟函数:

I'm doing some experimenting with x86-64 assembly. Having compiled this dummy function:

long myfunc(long a, long b, long c, long d,
            long e, long f, long g, long h)
{
    long xx = a * b * c * d * e * f * g * h;
    long yy = a + b + c + d + e + f + g + h;
    long zz = utilfunc(xx, yy, xx % yy);
    return zz + 20;
}

使用 gcc的-O0 -g 我惊讶地发现,在函数的程序集的开头如下:

With gcc -O0 -g I was surprised to find the following in the beginning of the function's assembly:

0000000000400520 <myfunc>:
  400520:       55                      push   rbp
  400521:       48 89 e5                mov    rbp,rsp
  400524:       48 83 ec 50             sub    rsp,0x50
  400528:       48 89 7d d8             mov    QWORD PTR [rbp-0x28],rdi
  40052c:       48 89 75 d0             mov    QWORD PTR [rbp-0x30],rsi
  400530:       48 89 55 c8             mov    QWORD PTR [rbp-0x38],rdx
  400534:       48 89 4d c0             mov    QWORD PTR [rbp-0x40],rcx
  400538:       4c 89 45 b8             mov    QWORD PTR [rbp-0x48],r8
  40053c:       4c 89 4d b0             mov    QWORD PTR [rbp-0x50],r9
  400540:       48 8b 45 d8             mov    rax,QWORD PTR [rbp-0x28]
  400544:       48 0f af 45 d0          imul   rax,QWORD PTR [rbp-0x30]
  400549:       48 0f af 45 c8          imul   rax,QWORD PTR [rbp-0x38]
  40054e:       48 0f af 45 c0          imul   rax,QWORD PTR [rbp-0x40]
  400553:       48 0f af 45 b8          imul   rax,QWORD PTR [rbp-0x48]
  400558:       48 0f af 45 b0          imul   rax,QWORD PTR [rbp-0x50]
  40055d:       48 0f af 45 10          imul   rax,QWORD PTR [rbp+0x10]
  400562:       48 0f af 45 18          imul   rax,QWORD PTR [rbp+0x18]

GCC 很奇怪溢出所有参数寄存器到堆栈中,然后带他们从内存中进行进一步的操作。

gcc very strangely spills all argument registers onto the stack and then takes them from memory for further operations.

这只是发生在 -O0 (用 -O1 不存在任何问题),不过,为什么呢?这看起来像一个反优化我 - 为什么会 GCC

This only happens on -O0 (with -O1 there are no problems), but still, why? This looks like an anti-optimization to me - why would gcc do that?

推荐答案

我绝不是一个GCC内部的专家,但我给它一个镜头。不幸的是大多数对GCCS信息寄存器分配和溢出似乎是过时(引用文件,就像不存在了本地alloc.c )的。

I am by no means a GCC internals expert, but I'll give it a shot. Unfortunately most of the information on GCCs register allocation and spilling seems to be out of date (referencing files like local-alloc.c that don't exist anymore).

我期待在源$ C ​​$ C GCC-4.5-20110825

I'm looking at the source code of gcc-4.5-20110825.

GNU C编译器内部中提到,最初的功能code是由<$产生C $ C> expand_function_start 在的gcc / function.c 。在那里,我们找到处理参数如下:

In GNU C Compiler Internals it is mentioned that the initial function code is generated by expand_function_start in gcc/function.c. There we find the following for handling parameters:

4462   /* Initialize rtx for parameters and local variables.
4463      In some cases this requires emitting insns.  */
4464   assign_parms (subr);

assign_parms 的code,处理每个参数存储如下:

In assign_parms the code that handles where each arguments is stored is the following:

3207       if (assign_parm_setup_block_p (&data))
3208         assign_parm_setup_block (&all, parm, &data);
3209       else if (data.passed_pointer || use_register_for_decl (parm))
3210         assign_parm_setup_reg (&all, parm, &data);
3211       else
3212         assign_parm_setup_stack (&all, parm, &data);

assign_parm_setup_block_p 处理聚合数据类型和不适用在这种情况下,并且由于数据不作为指针GCC检查传递 use_register_for_decl

assign_parm_setup_block_p handles aggregate data types and is not applicable in this case and since the data is not passed as a pointer GCC checks use_register_for_decl.

下面的相关部分是:

1972   if (optimize)
1973     return true;
1974 
1975   if (!DECL_REGISTER (decl))
1976     return false;

DECL_REGISTER 测试变量是否是与注册关键字来声明。现在,我们有我们的答案是:大多数参数住在栈上没有启用优化时,并且然后由 assign_parm_setup_stack 处理。通过源$ C ​​$ C所走的路线就结束了溢出值略有是指针参数比较复杂,但允许在同一个文件,如果你很好奇被跟踪。

DECL_REGISTER tests whether the variable was declared with the register keyword. And now we have our answer: Most parameters live on the stack when optimizations are not enabled, and are then handled by assign_parm_setup_stack. The route taken through the source code before it ends up spilling the value is slightly more complicated for pointer arguments, but can be traced in the same file if you're curious.

为什么GCC漏油事件的所有参数和优化本地变量禁用?为了帮助调试。考虑一下这个简单的函数:

Why does GCC spill all arguments and local variables with optimizations disabled? To help debugging. Consider this simple function:

1 extern int bar(int);
2 int foo(int a) {
3         int b = bar(a | 1);
4         b += 42;
5         return b;
6 }

的gcc -O1 -c 编译这会产生我的机器上执行以下操作:

Compiled with gcc -O1 -c this generates the following on my machine:

 0: 48 83 ec 08             sub    $0x8,%rsp
 4: 83 cf 01                or     $0x1,%edi
 7: e8 00 00 00 00          callq  c <foo+0xc>
 c: 83 c0 2a                add    $0x2a,%eax
 f: 48 83 c4 08             add    $0x8,%rsp
13: c3                      retq   

除非你在第5行突破和尝试打印a的值,它是很好,你得到

Which is fine except if you break on line 5 and try to print the value of a, you get

(gdb) print a
$1 = <value optimized out>

作为参数被覆盖,因为它没有调用后使用。

这篇关于海湾合作委员会的说法寄存器溢出X86-64上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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