在程序集中将浮点值打印到 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 缓冲区)发生,则只需 retcall 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 内联到您的主函数中,您可以使用 fstpldouble 放在指向格式字符串的指针正上方的堆栈中。

或者让您的 pfl 函数在 %st(0) 而不是整数寄存器中获取输入,因为无论如何您都在制定自定义调用约定。

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