Does the floating point stack change when moving to and from a procedure?

Started by mlhrechun, March 30, 2008, 04:38:01 AM

Previous topic - Next topic

mlhrechun

I ask this because I'm currently working on a class assignment where I must read in a floating point number (into a local variable) then place it into an array that is local to procedure that called the number reader.

Right now i'm using the fpstack to try to transfer it (made sense to me at first).

I know i'm putting it into the stack correctly (tested it) yet once I get back to the procedure with the array, attempting to pop the stack into a Real8 and then converting it to a str with FloatToStr and printing that out just gives me a bunch of ascii gibberish.

That only happens when i actually have a floating point number to transfer, if i enter 3.0, for instance, it works fine since it can truncate the .0 etc.

Well, any insight as to what I'm doing wrong? Is it naive to thing the fpstack won't change between two procedures? If it is, then why is it working for integers but not for reals?

Tedd

The floating-point registers shouldn't change unless you explicitly change them - so no, not between procedures. In fact, it's common to return a floating-point value in st(0). (You do mean fp-registers by "stack" don't you, and not the stack [esp] - which does change between procs.)
The first thing that comes to mind if it's working for int, but not real8, is that you're only taking the first 4 bytes of the real..
If you post your code (or a cut down version that still has the problem) then we can take a look at where you're going wrong, instead of trying to guess :P
No snowflake in an avalanche feels responsible.

mlhrechun

Quote from: Tedd on March 30, 2008, 09:53:47 AM
The floating-point registers shouldn't change unless you explicitly change them - so no, not between procedures. In fact, it's common to return a floating-point value in st(0). (You do mean fp-registers by "stack" don't you, and not the stack [esp] - which does change between procs.)
The first thing that comes to mind if it's working for int, but not real8, is that you're only taking the first 4 bytes of the real..
If you post your code (or a cut down version that still has the problem) then we can take a look at where you're going wrong, instead of trying to guess :P


Yeah that's exactly what I mean, I'm trying to pass it back through St(0) of the fp-registers.

Here you go...

The loop in my main proc. Note that enteredFP is declared locally as a Real8. Also, there is code to copy what's in enteredFP into the array, but i commented it out since the main problem is with getting enteredFP to be correct at all.
ARRAYMAKER:
finit

push ecx

call  enterValue
fstp enteredFP

invoke FloatToStr2, enteredFP, ADDR answer3
invoke  StdOut, ADDR answer3
pop ecx

;lea ebx, enteredFP

;Move first half of QWORD into first half of array's QWORD...
;mov eax, [ebx]
;mov [esi], eax

;Move second half of QWORD into second half of array's QWORD...
;mov eax, [ebx+4]
;mov [esi+4], eax

;add esi, 8

loop ARRAYMAKER


And here's the proc entervalue
enterValue proc
LOCAL entry:DWORD
LOCAL myFP:REAL8
LOCAL myFP2:REAL8
LOCAL answer[20]:BYTE

print chr$("Enter a floating point number: ")
invoke StdIn, ADDR entry, 128
invoke StrToFloat, ADDR entry, ADDR myFP

invoke FloatToStr2, myFP, ADDR answer
        invoke  StdOut, ADDR answer

fld myFP

fst myFP2
invoke FloatToStr2, myFP2, ADDR answer
        invoke  StdOut, ADDR answer
ret
enterValue endp


As you can see in the enterValue proc I print out the read in float instantly to check for correct reading (it prints out perfectly), then I put it on the stack and take it of the stack (that prints out correctly as well).

Yet when I try to pop off the stack in the main procedure (where the arraymaker loop is), the part after the decimal is mangled horribly!

I appreciate your help :)

Some example input and output would be something like
You enter 1.0 for the float
"1 1 1"
You enter 2.8 for the float
"2.8 2.8 (ascii gibberish)"

Oddly enough if I don't push and pop ecx (which I do to preserve the loop counter) I get different output, that is the area beyond the decimal point is always .4 as opposed to ascii gibberish.

MichaelW

The FPU part of your code appears to be OK. Everything is being displayed on one line because your code is not passing any line breaks to StdOut. You could correct this by defining a null-terminated string that contains the ascii codes 13 and 10, and following each of the calls to StdOut with another call that passes this string. Another problem is with:

LOCAL entry:DWORD

Where entry actually needs to be a buffer long enough to hold the input string. And since the ReadFile function that StdIn calls does not null terminate the buffer, and StrToFloat expects a null-terminated string, and LOCALs are not automatically initialized, you should zero the buffer before you use it with something like this:

invoke memfill, ADDR entry, whatever_length_you_selected, 0

And in the call to StdIn you should specify one less than the length you selected, so it will pass the length to ReadFile, so the user will not be able to overflow the buffer or overwrite the null terminator.
eschew obfuscation

mlhrechun

Quote from: MichaelW on March 30, 2008, 07:05:53 PM
The FPU part of your code appears to be OK. Everything is being displayed on one line because your code is not passing any line breaks to StdOut. You could correct this by defining a null-terminated string that contains the ascii codes 13 and 10, and following each of the calls to StdOut with another call that passes this string. Another problem is with:

LOCAL entry:DWORD

Where entry actually needs to be a buffer long enough to hold the input string. And since the ReadFile function that StdIn calls does not null terminate the buffer, and StrToFloat expects a null-terminated string, and LOCALs are not automatically initialized, you should zero the buffer before you use it with something like this:

invoke memfill, ADDR entry, whatever_length_you_selected, 0

And in the call to StdIn you should specify one less than the length you selected, so it will pass the length to ReadFile, so the user will not be able to overflow the buffer or overwrite the null terminator.


Thank you so much! Yeah the StdIn things you specified were what was causing my problem. I made the changes you mentioned and now it works perfectly.

Thanks again!