Title: How can I operate with float point numbers in assembly?
Tags: c;assembly;x86;masm;x87
Question: I need to send two real numbers from C (using extern 'C' double (double num1,double num2)) to a assembly procedure that returns the addition of these numbers. I don't know  how to do this  yet.
I tried this but it didn't work.
res dq 0
procSuma proc num1,num2
fld num1   ; load num1 and push it onto the fpu stack
fld num2   ; load num2 and push it onto the fpu stack
faddp      ; pop two numbers, add them, push sum on the stack
fstp res   ; pop sum from the stack and store it in res
procSuma endp
Comment: The calling convention on Windows says that st(0) should contain the return value for a double. So you should be able to eliminate the `res` variable altogether, get rid of of `fstp res`. `faddp` should have added the two value and put the result in `st(0)`, so you should only have to do `ret` right after. Since you are passing double floats into _procSuma_ you should change `procSuma proc num1,num2` to `procSuma proc num1:REAL8,num2:REAL8` so MASM knows your two parameters are REAL8(8 bytes)

Comment: One other issue could be that you should specify `PROC C` instead of `PROC` so that MASM sets the procedure up using C calling convention. So `procSuma proc num1:REAL8,num2:REAL8` should probably be `procSuma proc C num1:REAL8,num2:REAL8`

Comment: FYI, learning x87 FPU is not tremendously useful in 2015.  If you really want to, there's a good tutorial linked from [the x86 tag wiki](http://stackoverflow.com/tags/x86/info).  For new code, use SSE/SSE2, unless you need backwards compat with ancient 32bit-only CPUs (e.g. Athlon XP was the last CPU to *not* support SSE2).  The 32bit ABI returns floating point results in `st(0)`, so you can't avoid it completely in 32bit code, which is another reason 32bit sucks and should be considered obsolete.

Comment: Please clearly state the expected output and the output you actually get in your question

Comment: it didn't produce the right result.

Comment: @PeterCordes The x87 instruction set still provides extended-double format and operations with 64 bits of precision, and is very useful in 2015 for this reason. There is little reason to use it from assembly, though.

Comment: "didn't work" means what? Didn't compile, didn't produce the right result, something else?


Here is another answer: Where you went wrong is you copy pasted code that was originally not contained in a function into a function, which I believe you got from here.  Adding floating point/double numbers in assembly
Since the assembly code is now contained within a proc, a variable is no longer needed to store the result because the result is stored on the stack at the address of st(0), which would be your return value. When fstp is called, it pops the stack (Hint: the p at the end) so your return value stored at st(0) is no longer valid. Removing the fstp instuction will give you the intended result.
Step by step this is what the code is doing.
procSuma proc num1,num2
fld num1   ; This pushes num1 onto the stack at the address of st(0)
fld num2   ; This pushes num2 onto the stack at the address of st(1)
faddp      ; This multiplies st(1) and st(0), stores the result at st(0), and then pops the variable stored at st(1) off the stack
fstp res   ; !REMOVE THIS. This is why you aren't getting the expected result.It pops the variable in st(0) off the stack, which is your return value.
procSuma endp
Comment for this answer: Thank you, @PeterCordes . It is a "just get it working answer" The reloading of res would be redundant and cargo cultish.
Comment for this answer: Welcome to SO.  This would be a better answer if you explained *why* the result needs to be in `st(0)`, instead of some randomly-named global he made up.  (i.e. because of the Windows x86 32bit ABI).  Also, suggesting re-loading with `fld` after storing is just confusing.
Comment for this answer: Michael Petch's answer-in-comments is much better than this answer, because it explains they reason.  This answer doesn't do much to help a confused newbie understand what's going on, and so isn't very long-term useful to anyone else whose google search turns up this Q&A.

Here is another answer: I'm assuming this is a homework assignment that requires you to use x87 FPU instructions. Alternatively you could be using SSE/SSE2 SIMD instructions to perform the addition.
C calling (cdecl) convention on Win32 requires single and double precision floats to be returned in ST(0) (register on top of the FPU stack). Since faddp adds two numbers and places the result in ST(0) means that we don't need any temporary variables to store the result. These lines can then be removed:
res dq 0
fstp res   ; pop sum from the stack and store it in res
When creating a procedure you should specify the size of the arguments being passed so that MASM knows exactly what size the operands are for operations. To ensure you are using double precision values mark the double arguments as REAL8 (8 byte REALS). You should also mark the PROC as using C calling convention with PROC C so the stack and the arguments are properly set up and addressed. The procedure declaration should look like:
procSuma proc C num1:REAL8,num2:REAL8
The resulting code could look like:
.model flat, c
procSuma proc C num1:REAL8,num2:REAL8
fld num1   ; load num1 and push it onto the fpu stack
fld num2   ; load num2 and push it onto the fpu stack
faddp      ; pop two numbers, add them, push sum on the stack.
; result in st(0) (top of FPU stack)
; We return double values in st(0) so nothing to do
; since faddp put our result in st(0)
ret
procSuma endp
You could reduce the addition to a couple instructions by using FADD instead of FADDP:
fld num1   ; load num1 and push it onto the fpu stack
fadd num2  ; Add ST(0)(num1) to num2 and store result in ST(0).
; We return double values in st(0) so nothing to do
; since fadd put our result in st(0)

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 7, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2015:00:11/15/15', 'FavoriteCount': 1.0, 'PostTypeId': 1, 'Tags': '<c><assembly><x86><masm><x87>', 'Title': 'How can I operate with float point numbers in assembly?', 'ViewCount': 4226, 'id': 33716006, 'user_AboutMe': None, 'user_AccountId': 6122618.0, 'user_DisplayName': 'Christian Salazar', 'user_Reputation': 31.0, 'user_Views': 11.0, 'user_id': 5563372.0}}