在程序集 linux 中将浮点值打印到 STDOUT [英] Printing Float Value to STDOUT in assembly linux

查看:42
本文介绍了在程序集 linux 中将浮点值打印到 STDOUT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将浮点值打印到控制台,但它给出了意外的结果,因为数字太大且符号不同.

计划

.datafloat_: .asciz "%f\n"n1: .float 10.4n2: .float 10.3.文本.globl 主主要的:低于 1 美元,%esp结束flds n1fsubs n2fsts 1(%esp)movl 1(%esp), %eax呼叫 pfladdl $1, %esp.出口:movl $1, %eaxmovl $0, %ebx整数 $0x80pfl:推动推 %eax推$浮动_调用 printf加 8 美元,%esp流行的回复

输出

每次都不同,但介于 -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 缓冲区)发生,则只需 retcall exit.否则,如果您将 stdout 重定向到一个文件,因此它是全缓冲的,您将不会得到任何输出.

这是修复上述所有问题的可能版本:

.datafloat_: .asciz "%f\n"n1: .float 10.4n2: .float 10.3.文本.globl 主主要的:sub $12, %esp # 8 字节用于双精度,+ 4 字节用于对齐flds n1fsubs n2fstpl (%esp) # 从 fpu 弹出 doublemovl (%esp), %eax # 低 4 字节movl 4(%esp), %edx # 高 4 字节呼叫 pfl加 12 美元,%esp回复## 输入:EDX:EAX = 双精度位模式pfl:推 %edx推 %eaxpush $float_ # 3x push 再次将堆栈重新对齐 16调用 printf加 12 美元,%esp回复

通过整数寄存器来回弹你的 double 是不必要的;如果您将 call printf 内联到您的主函数中,您可以只使用 fstpldouble 放在堆栈中指向格式指针的正上方细绳.

或者让你的 pfl 函数在 %st(0) 中接受它的输入,而不是整数寄存器,因为无论如何你都在制定自定义调用约定.>

(我假设您的下一个问题将是为什么它打印 0.099999 而不是 0.1 :))

I'm trying to print float values to console but it gives unexpected results too large number having different sign.

Program

.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

Output

Different every time but between -400...0.0... to -500000..0.0...

解决方案

Various problems with your code. Most importantly, %f expects a double but you pass a float. See man 3 printf or a C book. Furthermore a float is 4 bytes so you'd be well advised to allocate 4 bytes not 1. To make matters worse, you are not even using the 1 byte allocated since that is at (%esp) but you used 1(%esp). For a double you will need 8 bytes. Next, you forgot to pop the value from the FPU. Also, current calling conventions require 16 byte aligned stack, even in 32 bit mode.

Finally, it's not recommended to use the exit system call directly in main or other code that uses libc function. Instead, just ret or call exit if you really insist to make sure libc cleanup (like flushing stdio buffers) happens. Otherwise you'll get no output if you redirect stdout to a file so it's full-buffered.

Here is a possible version fixing all of the above:

.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

Bouncing your double through integer registers is unnecessary; if you inlined call printf into your main function you could have just used fstpl to put the double on the stack right above a pointer to the format string.

Or made your pfl function takes its input in %st(0) instead of integer registers, since you're making up a custom calling convention anyway.

(I assume your next question is going to be why it prints 0.099999 instead of 0.1 :))

这篇关于在程序集 linux 中将浮点值打印到 STDOUT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆