Art*_*cto 1 c linux 64-bit printf calling-convention
#include <stdio.h>
int main(void)
{
double resd = 0.000116;
long long resi = 0;
printf("%lld %f %lld %f\n", resd, resd, resi, resi);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给出(Linux,gcc,x64)
0 0.000116 0 0.000116
^^^^^^^^ odd, since the memory for resi is zeroed
实际上,用g ++编译它会得到随机结果,而不是第二个0.
我理解我给了无效的说明符printf并触发它不明未定义的行为,但我想知道为什么会发生这种特定的损坏,因为long long并且double具有相同的大小.
Ste*_*non 10
这是因为在x86_64C调用你的平台上约定,前两个浮点参数在传递xmm0和xmm1,和前两个整型参数在GPRS传送(rsi和rdx如果你在Linux或OS X),不分先后顺序的它们出现在哪里.
你很困惑,因为你期望参数在内存中传递; 他们不是.
我得到的结果与我的机器相同(Mac OS X,AMD/Linux ABI).浮点参数在XMM寄存器中传递,整数参数在整数寄存器中传递.当printf使用va_arg它时,它会在看到%f格式时从XMM中拉出,在看到时从其他寄存器中拉出%lld.这是-O0我的机器上的编译()程序的反汇编:
1 _main:
2 pushq %rbp
3 movq %rsp,%rbp
4 subq $0x20,%rsp
5 movq $0x3f1e68a0d349be90,%rax
6 move %rax,0xf8(%rbp)
7 movq $0x00000000,0xf0(%rbp)
8 movq 0xf0(%rbp),%rdx
9 movq 0xf0(%rbp),%rsi
10 movsd 0xf8(%rbp),%xmm0
11 movq 0xf8(%rbp),%rax
12 movapd %xmm0,%xmm1
13 movq %rax,0xe8(%rbp)
14 movsd 0xe8(%rbp),%xmm0
15 lea 0x0000001d(%rip),%rdi
16 movl $0x00000002,%eax
17 callq 0x100000f22 ; symbol stub for: _printf
18 movl $0x00000000,%eax
19 leave
20 ret
Run Code Online (Sandbox Code Playgroud)
在那里,你可以看到这是怎么回事-格式字符串传递的%rdi,那么你的参数传递(按顺序)中: %xmm0,%xmm1,%rsi,和%rdx.如果printf
赢了钱,它会弹出发挥他们在不同的顺序(在你的格式字符串指定的顺序).这意味着它会弹出他们: %rsi,%xmm0,%rdx,%xmm1,让您看到的结果.该2中%eax是指示传递浮点参数的个数.
编辑:
这是一个优化版本 - 在这种情况下,较短的代码可能更容易理解.解释与上面相同,但是样板噪声稍微小一些.浮点值由movsd在线4 加载.
1 _main:
2 pushq %rbp
3 movq %rsp,%rbp
4 movsd 0x00000038(%rip),%xmm0
5 xorl %edx,%edx
6 xorl %esi,%esi
7 movaps %xmm0,%xmm1
8 leaq 0x00000018(%rip),%rdi
9 movb $0x02,%al
10 callq 0x100000f18 ; symbol stub for: _printf
11 xorl %eax,%eax
12 leave
13 ret
Run Code Online (Sandbox Code Playgroud)