在程序集中将浮点值打印到 STDOUT linux
Printing Float Value to STDOUT in assembly linux
我正在尝试将浮点值打印到控制台,但它给出了意想不到的结果,因为数字太大且符号不同。
计划
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub , %esp
finit
flds n1
fsubs n2
fsts 1(%esp)
movl 1(%esp), %eax
call pfl
addl , %esp
.exit:
movl , %eax
movl [=11=], %ebx
int [=11=]x80
pfl:
pushal
push %eax
push $float_
call printf
add , %esp
popal
ret
输出
每次都不同,但介于 -400...0.0... 到 -500000..0.0...
您的代码存在各种问题。最重要的是,%f
期望 double
但你传递了 float
。请参阅 man 3 printf 或 C 语言书籍。此外,float
是 4 个字节,因此建议您分配 4 个字节而不是 1 个字节。更糟糕的是,您甚至没有使用分配的 1 个字节,因为它位于 (%esp)
但您使用了1(%esp)
。对于双精度,您将需要 8 个字节。接下来,您忘记从 FPU 弹出值。此外,当前的调用约定需要 16 字节对齐的堆栈,即使在 32 位模式下也是如此。
最后,不建议在main
或其他使用libc函数的代码中直接使用exit系统调用。相反,如果您真的坚持要确保 libc 清理(如刷新 stdio 缓冲区)发生,则只需 ret
或 call exit
。否则,如果您将 stdout 重定向到一个文件,那么它是 full-buffered.
,您将得不到任何输出
这是修复以上所有问题的可能版本:
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub , %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 , %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 , %esp
ret
不需要通过整数寄存器弹回 double
;如果您将 call printf
内联到您的主函数中,您可以使用 fstpl
将 double
放在指向格式字符串的指针正上方的堆栈中。
或者让您的 pfl
函数在 %st(0)
而不是整数寄存器中获取输入,因为无论如何您都在制定自定义调用约定。
(我假设你的下一个问题是为什么它打印 0.099999
而不是 0.1
:))
我正在尝试将浮点值打印到控制台,但它给出了意想不到的结果,因为数字太大且符号不同。
计划
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub , %esp
finit
flds n1
fsubs n2
fsts 1(%esp)
movl 1(%esp), %eax
call pfl
addl , %esp
.exit:
movl , %eax
movl [=11=], %ebx
int [=11=]x80
pfl:
pushal
push %eax
push $float_
call printf
add , %esp
popal
ret
输出
每次都不同,但介于 -400...0.0... 到 -500000..0.0...
您的代码存在各种问题。最重要的是,%f
期望 double
但你传递了 float
。请参阅 man 3 printf 或 C 语言书籍。此外,float
是 4 个字节,因此建议您分配 4 个字节而不是 1 个字节。更糟糕的是,您甚至没有使用分配的 1 个字节,因为它位于 (%esp)
但您使用了1(%esp)
。对于双精度,您将需要 8 个字节。接下来,您忘记从 FPU 弹出值。此外,当前的调用约定需要 16 字节对齐的堆栈,即使在 32 位模式下也是如此。
最后,不建议在main
或其他使用libc函数的代码中直接使用exit系统调用。相反,如果您真的坚持要确保 libc 清理(如刷新 stdio 缓冲区)发生,则只需 ret
或 call exit
。否则,如果您将 stdout 重定向到一个文件,那么它是 full-buffered.
这是修复以上所有问题的可能版本:
.data
float_: .asciz "%f\n"
n1: .float 10.4
n2: .float 10.3
.text
.globl main
main:
sub , %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 , %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 , %esp
ret
不需要通过整数寄存器弹回 double
;如果您将 call printf
内联到您的主函数中,您可以使用 fstpl
将 double
放在指向格式字符串的指针正上方的堆栈中。
或者让您的 pfl
函数在 %st(0)
而不是整数寄存器中获取输入,因为无论如何您都在制定自定义调用约定。
(我假设你的下一个问题是为什么它打印 0.099999
而不是 0.1
:))