海湾合作委员会的说法寄存器溢出X86-64上 [英] gcc argument register spilling on 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屋!