I’m currently studying Simply FPU tutorial. So as exercise for myself, I’d like to learn how to divide floating points in assembly. Let’s say I’m going to divide 48.6 by 17.1. Here’s the code.
format PE console 4.0
entry main
include 'win32a.inc'
section '.data' data readable writeable
num1 dq 48.6
num2 dq 17.1
result dq ?
fmt db "%g", 10
szBuff db 32 dup (0)
section '.code' code readable executable
main:
fld qword [num1]
fld qword [num2]
fdivp
fstp qword [result]
invoke printf, fmt, result
invoke ExitProcess, 0
section '.idata' import data readable
library kernel32,'kernel32.dll', msvcrt,'msvcrt.dll'
import kernel32, ExitProcess,'ExitProcess'
import msvcrt, printf, 'printf'
The output of the code is
7.62883e+265
What goes wrong here?
As suggested by Jester, I examined the code using OllyDbg

I guess the result was correct, but somehow it was messed up by printf?
Upvote for using that tutorial, it’s very good 🙂
A couple problems there:
st(0)andst(7)they will best(1)andst(0). The register numbering is fixed, it’s alwaysst(0)at the top, but the barrel turns. When you load something it will best(0). If you load something else afterwards, the barrel rotates, and what you previously had will move tost(1)and the current value will be put inst(0).such as for the
fldand thefstinvokemacro knows how to pass floating pointarguments to
printfit’s just a general problem)
I recommend you use a debugger to single step the code, so you can see what’s happening and you don’t even need to mess with trying to use
printf.Update: sample session using gdb on linux with a working code (edited for clarity):
Note that
gdbprints the instruction that’s gonna be executed next. The FPU stack top is marked by the arrow, that’s alwaysst(0)by definition. It is followed by the others in increasing order and wraparound if necessary. The first dump shows48.6being loaded intost(0)because that’s marked by the arrow, the other locations are empty. Then,17.1is being loaded intost(0)again because the arrow has moved (the barrel rotated). The48.6is nowst(1).FDIVPperforms the division and removes one item from the stack, so we end up with result inst(0)and the rest empty.FSTPthen storesst(0)for theprintfas argument and removes it from the stack, so all registers are now empty.