Assembly 为什么要分解“printf”(“f”,6.4)`这么复杂?

Assembly 为什么要分解“printf”(“f”,6.4)`这么复杂?,assembly,floating-point,Assembly,Floating Point,第一个浮点参数被赋予xmm0、xmm1。。。在x86-64 ABI中。 没有直接将立即数(6.4的浮点表示)移动到xmm寄存器的指令,因此它首先放在堆栈上,然后移动到xmm0中。当然,另一个参数是格式字符串的地址 $1和1之间的差值第一个用作立即常数,第二个用作地址偏移量或地址。第一个浮点参数被赋予xmm0、xmm1。。。在x86-64 ABI中。 没有直接将立即数(6.4的浮点表示)移动到xmm寄存器的指令,因此它首先放在堆栈上,然后移动到xmm0中。当然,另一个参数是格式字符串的地址 $1和

第一个浮点参数被赋予xmm0、xmm1。。。在x86-64 ABI中。 没有直接将立即数(6.4的浮点表示)移动到xmm寄存器的指令,因此它首先放在堆栈上,然后移动到xmm0中。当然,另一个参数是格式字符串的地址


$1和1之间的差值第一个用作立即常数,第二个用作地址偏移量或地址。

第一个浮点参数被赋予xmm0、xmm1。。。在x86-64 ABI中。 没有直接将立即数(6.4的浮点表示)移动到xmm寄存器的指令,因此它首先放在堆栈上,然后移动到xmm0中。当然,另一个参数是格式字符串的地址


$1和1之间的差值是第一个用作立即常数,第二个用作地址偏移量或地址。

因为编译时没有进行任何优化。尝试
-Os

(gdb) p 0x10
$4 = 16
(gdb) p $0x10
$5 = void

这有什么复杂的呢?

因为您在编译时没有进行任何优化。尝试
-Os

(gdb) p 0x10
$4 = 16
(gdb) p $0x10
$5 = void


这有什么复杂的呢?

因为如果简单的话,你就不会问,问题也不会结束。哪里是“复杂的”?这只是一些说明。顺便说一句,0x40199999999a是6.4文本的十六进制值。@Paul R,为什么浮点首先移动到rax,然后是堆栈,最后是目标xmm0?谁知道呢?这取决于您使用的编译器、ABI和优化级别。对我来说,在MacOSX上使用
gcc-O3
我只得到4条指令:
movsd-LC0(%rip),%xmm0;leaq LC1(%rip),%rdi;movl$1,%eax;调用_printf
我使用的是gcc,在编译时不使用任何优化标志(
gcc-Wall-g
),也不知道它使用的是哪种ABI。因为如果它很简单,你就不会问,问题也不会结束。它“复杂”在哪里?这只是一些说明。顺便说一句,0x40199999999a是6.4文本的十六进制值。@Paul R,为什么浮点首先移动到rax,然后是堆栈,最后是目标xmm0?谁知道呢?这取决于您使用的编译器、ABI和优化级别。对我来说,在MacOSX上使用
gcc-O3
我只得到4条指令:
movsd-LC0(%rip),%xmm0;leaq LC1(%rip),%rdi;movl$1,%eax;调用_printf
我正在使用gcc,在编译时不使用任何优化标志(
gcc-Wall-g
),也不知道它使用的是哪一个ABI。为什么必须首先将它放在堆栈上?它不能直接从寄存器
rax
移动到
xmm0
?因为
printf
使用的参数数量可变(使用
)语法。通过在堆栈上传递它们,
printf
函数可以很容易地检索它们。有些体系结构在寄存器中传递此类参数,但这里不是这样。@Lindydancer,
printf
不是最终从
xmm0
获取浮点参数吗?可能,我不知道这一点r调用约定。如果是,代码序列看起来奇怪地长。可能它是保守的,并将其存储在堆栈和寄存器中,以便
printf
可以在有或没有FPU支持的情况下实现(尽管有点牵强)。直接从rax移动到xmm0是可能的,但您需要一些优化标志。它需要特殊的SSE指令(由于x86_64,可能会启用)编译器需要知道应该针对哪种体系结构进行优化—例如,在P4上,对内存的读写比从通用寄存器移动到sse寄存器要快。为什么必须首先将它放在堆栈上?它不能直接从寄存器
rax
移动到
xmm0
?因为
printf
需要变量数量的参数(使用
)语法。通过在堆栈上传递它们,
printf
函数可以很容易地检索它们。有些体系结构在寄存器中传递此类参数,但这里不是这样。@Lindydancer,
printf
不是最终从
xmm0
获取浮点参数吗?可能,我不知道这一点r调用约定。如果是,代码序列看起来奇怪地长。可能它是保守的,并将其存储在堆栈和寄存器中,以便
printf
可以在有或没有FPU支持的情况下实现(尽管有点牵强)。直接从rax移动到xmm0是可能的,但您需要一些优化标志。它需要特殊的SSE指令(由于x86_64,可能会启用)对于编译器来说,需要知道应该针对哪种体系结构进行优化——例如,在P4上,对内存的读写比从通用寄存器到sse寄存器的移动要快
pushq   %rbp                     // save old frame pointer
movq    %rsp,  %rbp              // establish new frame pointer
leaq    0x0000004d(%rip), %rdi   // load address of format string ("%f")
movsd   0x0000003d(%rip), %xmm0  // load 6.4
movb    $0x01, %al               // load number of VA_ARGS (1)
callq   _printf                  // call printf
xorl    %eax,  %eax              // conjure return value (0)
popq    %rbp                     // restore frame pointer
ret                              // return