我试图在x86_64程序集中打印浮点数,但它只是将值打印为零。
已经有一些问题。通过确保you set the number of vector registers you're using in %al,似乎解决了一个问题。另一个表明you need to have a stack alignment of 16 bytes。但是,我正在做这两件事而仍然没有得到正确的输出。
这是我的计划:
# prints a floating point value
.section .rodata
.fmt: .string "num: %f\n"
.num: .float 123.4
.section .text
.global main
.type main, @function
main:
subq $8, %rsp # 16-byte alignment
# print my number
movss .num, %xmm0 # load float value
movq $.fmt, %rdi # load format string
movb $1, %al # use 1 vector register
call printf
# exit
addq $8, %rsp # undo alignment
movq $0, %rax # return 0
ret
答案 0 :(得分:8)
<强> printf(3)
's %f
format specifier wants a double
即可。无法让printf接受float
,仅double
或long double
。
C的默认参数提升指定对foo(char *fmt, ...)
等可变函数的调用将float
提升为double
,并执行通常的整数提升窄整数类型到int
,用于跟踪与原型的...
部分匹配的args。 (这同样适用于所有没有原型调用函数的args。)N1570 6.5.2.2 Function calls, subsections 6 and 7。
因此,C无法让调用者将float
传递给printf
,因此它没有转化,%f
表示double
< / strong>即可。 (%lf
也适用于double
,假设实现忽略了非整数/ wchar_t
转换。Accepting %lf
for double
is required in C99/C11 and C++11 printf
implementations,因此您可以安全地使用相同的%lf
格式字符串,double
和printf
的{{1}}。
请注意,scanf
不同,因为scanf
和float *
不受这些促销活动的影响。
double *
。如果你看compiler output,你会看到gcc做你所做的一切,CVTSS2SD .num, %xmm0
- 首先将寄存器归零以打破对{{1}的旧值的错误依赖}。 (cvtss2sd
糟糕的设计会使目标的高64位保持不变。)gcc会谨慎行事,并在许多情况下插入xor-zeroing指令以打破错误依赖。
您可能会得到0,因为xmm0的高位恰好为零。当pxor
将xmm0的低64位视为double
(IEEE binary64 on x86)时,它会在尾数的低32位中找到%xmm0
的位模式,其余为零。这代表一个非常小的(非正规)数字,因此它与printf
一起显示为零。
您可以尝试使用123.4f
的等效值(例如,在http://www.h-schmidt.net/FloatConverter/IEEE754.html上),在下半部分设置一些位以查看您获得的内容。
如果使用%f
(科学记数法)或float
(%g
位模式的十六进制表示),则会显示非零位。 (除非你在MXCSR中启用了Denormals Are Zero模式。)