Rohit
Rohit

Reputation: 17

Printing Float Value to STDOUT in assembly linux

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...

Upvotes: 0

Views: 507

Answers (1)

Jester
Jester

Reputation: 58762

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 :))

Upvotes: 3

Related Questions