Search code examples
floating-pointfpux86

Assembly IA32: Move 4 byte float from stack to FPU


At my university we are introduced to IA32/x86 assembler with AT&T Syntax. But the explanation lacks of important information.

How am I able to move a 4 byte float from the stack to the FPU? I tried with flds but it didn't work as expected...

EXAMPLE CODE:

.data
        fl:     .float 12.412
        test:   .string "Result: %f\n"

.text
.global main

main:
        # Prepare the stack (8 byte so i can use it for printf later)
        subl $8, %esp
        # Load the variable fl which holds 12.412
        fld fl
        # Store the previously loaded value as single precision (4 byte) to the stack
        fstps (%esp)
        # Load the value from the stack again and expect it to be single precision (as flds ends with s)
        flds (%esp)


        # Push it to the stack again. But this time as double precision value als printf expects floats to be 8 bytes long 
        fstp (%esp)
        pushl $test
        call printf

        movl $1, %eax
        int $0x80

But the output is:

Result: -0.491594

and not 12.412 as expected...

[EDIT:] Funny fact. Surprisingly the result changes for every single execution of the program.


Solution

  • I think the problem is that (right before you call printf) you use the wrong instruction to pop the FPU's top onto the stack. Your comment says "...this time as double precision...", but what you actually do with fstp is storing a single-precision value. Try fstpl and it will store a double-precision value.

    The fixed code should look something like this:

    .data
            fl:     .float 12.412
            test:   .string "Result: %f\n"
    
    .text
    .global main
    
    main:
            subl $8, %esp
            fld fl
            fstps (%esp)
            flds (%esp)
    
            fstpl (%esp)        # This line is the only one that has been changed.
            pushl $test
            call printf
    
            movl $1, %eax
            int $0x80