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