views:

324

answers:

3

I am working on a program which produces assembler code from expressions. One of the functions required is tan(x) which currently works using the following sequence of code (the addresses are filled in at run time):

fld [0x00C01288];
fld st(0);
fsin;
fld st(1);
fcos;
fdivp;
fst [0x0030FA8C];

However, I would like to use the FPTAN opcode instead, so I tried using the following code:

fld [0x00C01288];
fptan;
fincstp;
fst [0x0030FA8C];

The test program uses printf to show the result stored at 0x30FA8C, but for the second sequence the result is displayed as -1.#IND (the first using cos and sin works fine). If I try examining the value at the memory address, or on top of the floating point stack, in the debugger, it appears as the correct number.

So, my question is: Why is printf showing -1.#IND and how can I fix it?

The value at 0x00C01288 is double precision 0.5 The result in both cases is ~0.5463024898

My first thought was that the value being stored was a different representation of the same number, but inspecting the value stored at 0x0030FA8C shows it to be 0x3FE17B4F5BF3474A in both cases.

I do not understand why identical inputs to the printf function could produce different output...

Any help or suggestions would be greatly appreciated.

Edit: Source where printf is called:

#include "FridgeScript.h"
#include <stdio.h>
#include <math.h>

char test[] = "a=tan(0.5);";

int main(int c, char** s)
{
    unsigned int SC = FSCreateContext();

    double a = 0.0;
    FSRegisterVariable(SC, "a", &a);

    unsigned int CH = FSCompile(SC, test);
    if(CH) FSExecute(SC, CH);

    printf("a: %.10g\r\n", a);
    printf("hex a: %I64X", a);

    FSDestroyContext(SC);
    return 0;
}
+8  A: 

Let me just throw something out there: how about using

fstp st(0);

instead of

fincstp;

The docs on fincstp say it's not equivalent to popping the item from the stack because it leaves that spot tagged as filled - perhaps this is messing up the float handling inside of printf?

(You may be able to guess I don't know what I'm talking about. But maybe this will give you an idea?)

Jesse Rusak
This fixed it perfectly. Thanks. I suppose va_args relies on the floating point stack with printf's calling convention or something...
jheriko
Normally printf() uses the stack for parameters, and maybe some registers on x86-64. It knows how many parameters to seek by parsing the format string. IMO the problem was occuring when printf() tried to use FPU.
Bastien Léonard
That's a pretty darned good guess for someone who doesn't know what they're talking about :-) +1 for a good guess.
paxdiablo
Bastien - agreed. Perhaps there was a float stack overflow? As far as I can glean, that's what can happen when you leave stack entries marked as used.
Jesse Rusak
+1  A: 
fld [0x00C01288];
fptan;
fincstp;
fst [0x0030FA8C];

To me it looks like after this code executes, the tangent is still at st0. Shouldn't you use fstp instead of fst?

Bastien Léonard
This sounds related to my answer, too. The fp stack still has stuff in it.
Jesse Rusak
fst should store it at 0x0030FA8C, and the debugger shows that it is indeed written there. since st(0) is used for return values it must be left there as well so that the expressions can be like, e.g. "a = b = tan(0.5);"
jheriko
A: 

Maybe your FST instruction store just the float result, and the second dword is still uninitalized?

I don't see any size prefix in the assembly code. Usually you see something like:

  FST [dword ptr some_address]

  or 

  FS [qword ptr some_address]
Nils Pipenbrinck