I'm trying to print a floating point number by calling printf
but it seems to always just print the pi value (3.1415) although the result, which is supposed to be the area of a circle, is supposed to be moved to the pi variable after being calculated.
.section .data
value:
.quad 0
result:
.asciz "The result is %lf \n"
pi:
.double 3.14159
.section .bss
.section .text
.globl _start
.type area, @function
area:
nop
imulq %rbx, %rbx
movq %rbx, value
fildq value
fmul pi # multiply r^2 by pi
fst pi # Store result to pi
movupd pi, %xmm0 # move result to xmm0
nop
ret
_start:
nop
movq $2, %rbx
call area # calculate for radius 2
leaq result, %rdi
movq $1, %rax # specify only one float value
call printf
movq $0, %rdi # Exit
call exit
nop
I always get 3.1415 back. I dont know why as it's supposed to be overwritten by the fst
instruction.
You need to add a size suffix to your floating point operations if they happen to use memory operands. Otherwise, the GNU assembler will implicitly use single precision which is not what you want. To fix your code, change
fmul pi # multiply r^2 by pi
fst pi # Store result to pi
to
fmull pi # multiply r^2 by pi
fstl pi # Store result to pi
Some other remarks about your code:
use rip
-relative addressing modes instead of absolute addressing modes if possible. Specifically, this means to replace foo
with foo(%rip)
in your memory operands, including for lea result(%rip), %rdi
make sure to leave a clean x87 stack at the end of your functions or other code may spuriously cause it to overflow. For example, use fstpl pi(%rip)
to store the result and pop it off the stack.
use movsd
, not movupd
to load one double into an SSE register, not a pair.
consider using SSE instead of x87 if possible for all the math. It's the standard way to do scalar FP math in x86-64, that's why XMM registers are part of the calling convention. (Unless you need 80-bit extended precision, but you have a pi
constant in memory that's far less accurate than x87 fldpi
.)
...
cvtsi2sd %rbx, %xmm0
mulsd pi(%rip), %xmm0
ret