我正在尝试将浮点值打印到控制台,但是它给出了意外的结果,太大的数字具有不同的符号。
程序
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub $1, %esp
finit
flds n1
fsubs n2
fsts 1(%esp)
movl 1(%esp), %eax
call pfl
addl $1, %esp
.exit:
movl $1, %eax
movl $0, %ebx
int $0x80
pfl:
pushal
push %eax
push $float_
call printf
add $8, %esp
popal
ret
输出
每次都不同,但介于-400 ... 0.0 ...至-500000..0.0 ...
答案 0 :(得分:3)
您的代码存在各种问题。最重要的是,%f
期望double
,但是您传递了float
。参见man 3 printf或C书。此外,float
是4个字节,因此建议您分配4个字节而不是1个。更糟糕的是,您甚至没有使用分配的1个字节,因为它位于(%esp)
,但是您使用了1(%esp)
。对于双精度,您将需要8个字节。接下来,您忘记从FPU弹出值。另外,即使在32位模式下,当前的调用约定也需要16字节对齐的堆栈。
最后,建议不要直接在main
或其他使用libc函数的代码中使用退出系统调用。相反,如果您确实坚持要确保发生libc清理(如刷新stdio缓冲区),则只需ret
或call exit
。否则,如果将stdout重定向到文件以使其具有完整缓冲,则不会获得任何输出。
以下是可能的版本,可解决上述所有问题:
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub $12, %esp # 8 bytes for double, + 4 bytes for alignment
flds n1
fsubs n2
fstpl (%esp) # pop double from fpu
movl (%esp), %eax # low 4 bytes
movl 4(%esp), %edx # high 4 bytes
call pfl
addl $12, %esp
ret
## input: EDX:EAX = the bit-pattern for a double
pfl:
push %edx
push %eax
push $float_ # 3x push realigns the stack by 16 again
call printf
add $12, %esp
ret
不需要通过整数寄存器来启动double
;如果将call printf
内联到主函数中,则可能只是使用fstpl
将double
放在堆栈上指向格式字符串的指针的正上方。
或者使您的pfl
函数在%st(0)
中输入其输入,而不是在整数寄存器中输入,因为无论如何您都在建立自定义调用约定。
(我想您的下一个问题将是为什么它会打印0.099999
而不是0.1
:))