assemblyfloating-point64-bitnasmmingw-w64

NASM x64: Floating Point Part Incorrectly Printed as 0.000000


I'm a newbie to assembly and I tried to write an assembly program using NASM on Windows (x64) to extract and print the fractional part of a floating-point number. However, my program prints Floating Point Part: 0.000000 instead of the expected Floating Point Part: 0.500000.

Here is my current code:

section .data
    fmt db "Floating Point Part: %f", 10, 0
    float_value dq 10.5
    result dq 0.0

section .text
global main
extern printf

main:
    ; Function prologue
    push rbp
    mov rbp, rsp
    sub rsp, 32              ; Allocate shadow space

    ; Load floating-point value into the FPU
    fld qword [rel float_value]

    ; Call floatVal function
    call floatVal

    ; Store result from the FPU to memory
    fstp qword [rel result]

    ; Print the result using printf
    lea rcx, [rel fmt]       ; First argument: format string
    lea rdx, [rel result]    ; Second argument: address of result
    movsd xmm0, qword [rdx]  ; Move the double to xmm0 for printf
    call printf

    ; Function epilogue
    add rsp, 32              ; Deallocate shadow space
    mov eax, 0
    pop rbp
    ret

floatVal:
    ; Function prologue
    push rbp
    mov rbp, rsp
    sub rsp, 32              ; Allocate shadow space

    ; Get the integer part
    fld st0                  ; Copy the value to the top of the stack
    frndint                  ; Round to integer
    fsub                     ; Subtract integer part from original value (st0 - st1)

    ; Function epilogue
    add rsp, 32              ; Deallocate shadow space
    pop rbp
    ret

Compilation and Execution Steps:

nasm -f win64 flo.asm -o flo.o
gcc -m64 -o flo flo.o -lkernel32 -lmsvcrt
.\flo.exe

Expected Output:

Floating Point Part: 0.500000

Actual Output:

Floating Point Part: 0.000000

Environment:

What I've Tried:

The floating-point operations seem to be executed, but the result is not what I expect. It appears as though the result might be overwritten or not correctly passed to printf.

What exactly do I need to know

I'm very new to low-level programming and any help or suggestions would be greatly appreciated.

PS: I found the same problems published before in StackOverflow and I tried to update my code referring to them. They aren't working for me and my apologies for re-posting


Solution

  • According to calling convention, the second argument goes into xmm1 not xmm0. Also it should be duplicated into rdx. "Second argument: address of result" makes no sense as printf does not expect the address of a double. You should do:

    lea rcx, [rel fmt]       ; First argument: format string
    movsd xmm1, [rel result] ; Move the double to xmm1 for printf
    movq rdx, xmm1           ; duplicate second argument as per convention
    call printf
    

    Also in 64 bit mode you should generally avoid x87 FPU altogether. Leaf functions do not need to allocate shadow space.