Hi Guys,

I was working on a program that uses the FPU Reg. stack when I encountered something else that left me scratching my head. I pushed 8 values onto the FPU reg. stack, but trying to pop them brought about some strange (to me) results.

Please take a look at the ffg. makeshift program that illustrates:

//----------------------------------------------------------------------------------------------------
Program MyProg;
#include("stdlib.hhf")

procedure DisplayTOSPointer; // Store the status-word in and isolate only the TOS Pointer bits for display.
begin DisplayTOSPointer;
fstsw(ax);
and(%0011_1000_0000_0000, ax);
shr(11, ax);
stdout.put(nl, "The value in TOS pointer is ", ax);
end DisplayTOSPointer;

static
m_dFromStack: real32;

begin MyProg;

// Load eight real values into each of the FPU Stack Registers.
fld(7.2);
fld(6.2);
fld(5.2);
fld(4.2);
fld(3.2);
fld(2.2);
fld(1.2);
fld(0.2);

// Okay, now just pop all eight real values off the stack.
stdout.put(nl, nl, "Popped values:-");
for(mov(0, ecx); ecx < 8; inc(ecx)) do
DisplayTOSPointer();
fstp(m_dFromStack);
stdout.put("; ", m_dFromStack, " was popped off the stack.");
endfor;

end MyProg;
//----------------------------------------------------------------------------------------------------





When I compile and run, I get the ffg. output:

//----------------------------------------------------------------------------------------------------

Popped values:-
The value in TOS pointer is 0000; 0.000000000e+0 was popped off the stack.
The value in TOS pointer is 0000; 2.000000029e-1 was popped off the stack.
The value in TOS pointer is 0001; 1.200000047e+0 was popped off the stack.
The value in TOS pointer is 0002; 2.200000047e+0 was popped off the stack.
The value in TOS pointer is 0003; 3.200000047e+0 was popped off the stack.
The value in TOS pointer is 0004; 4.199999809e+0 was popped off the stack.
The value in TOS pointer is 0005; 5.199999809e+0 was popped off the stack.
The value in TOS pointer is 0006; 6.199999809e+0 was popped off the stack.
//-----------------------------------------------------------------------------------------------------




I was expecting the ffg. output:

//-----------------------------------------------------------------------------------------------------

The value in TOS pointer is 0000; 2.000000000e-1 was popped off the stack.
The value in TOS pointer is 0001; 1.200000047e+0 was popped off the stack.
...
The value in TOS pointer is 0007; 7.199999809e+0 was popped off the stack.
//-----------------------------------------------------------------------------------------------------


Why is the first instruction popping off 0 instead of 0.2?
Why isn't the value in the TOS pointer incrementing, thereafter, to point to the second register in the stack?




Thanks for all your help.
Posted on 2004-03-04 08:56:33 by Jaysen
Whenever you use an instruction such as fld(7.2) with your assembler program, you must realize that it is NOT a standard "Intel" instruction. It must be an internal HLL instruction which is most probably replaced by a macro to convert the value in brackets.

Such a macro also most probably uses the FPU to perform the conversion from alphanumeric to REAL numbers. And, to prevent any FPU "stack overflow", it should free any register required (at least 2) to perform that conversion. That would explain the loss of the first value (i.e. 7.2)you loaded to the FPU.

I would have to see the make-up of that conversion macro to properly explain the 0 for the first value you popped.

You must be very careful with those HLL instructions. They can be full of nasty surprises.

Another surprise I got recently was to realize that several API functions in WinXP have been rewritten to use MMX/SSE instruction (which use the FPU registers) without any regard to saving/restoring data already on the FPU.

Raymond
Posted on 2004-03-04 23:35:45 by Raymond
Wow, so brilliant!

Btw, I have briefly browsed your assembly site; a whole lot more information on the FPU as well. I'll definately make sure I read the FPU section before I move on in AoA.

Thanks a lot.
Posted on 2004-03-05 05:01:00 by Jaysen

Whenever you use an instruction such as fld(7.2) with your assembler program, you must realize that it is NOT a standard "Intel" instruction. It must be an internal HLL instruction which is most probably replaced by a macro to convert the value in brackets.


Actually, it's nothing sinister at all like this. fld(7.2) gets translated into


fld( compiler_named_memory_holding_7_2 );

and somewhere in the constant section it creates:


compiler_named_memory_holding_7_2 real80 7.2



Such a macro also most probably uses the FPU to perform the conversion from alphanumeric to REAL numbers. And, to prevent any FPU "stack overflow", it should free any register required (at least 2) to perform that conversion. That would explain the loss of the first value (i.e. 7.2)you loaded to the FPU.


Well, the compiler *does* use the FPU to do this conversion, but that's at compile-time, not at run-time. At run time, all the program sees is an FLD instruction specifying some memory address and the IEEE representation for 7.2 contained within that memory address.


I would have to see the make-up of that conversion macro to properly explain the 0 for the first value you popped.


I believe the above pretty much shows you what was done.


You must be very careful with those HLL instructions. They can be full of nasty surprises.

Nothing nasty about it. It's exactly what *you'd* want to do if you needed to load a literal constant onto the FPU stack.


Another surprise I got recently was to realize that several API functions in WinXP have been rewritten to use MMX/SSE instruction (which use the FPU registers) without any regard to saving/restoring data already on the FPU.

????!!!!
Actually, the SSE instructions do not use the FPU's register set, so I assume you mean MMX only. This would clearly be a bug in Win32 unless they've documented these effects. What functions were they?
Cheers,
Randy Hyde
Posted on 2004-03-05 16:26:01 by rhyde

Hi Guys,


Why is the first instruction popping off 0 instead of 0.2?
Why isn't the value in the TOS pointer incrementing, thereafter, to point to the second register in the stack?




Thanks for all your help.


Don't forget that the standard library routines that convert between FP format and string format need to use a few locations on the FPU stack. So what's happening here is that you push eight items on the stack, call stdout.put (which, ultimately, calls the FP->string conversion code), and that code uses the FPU for the conversion, causing a stack overflow. IIRC, it takes two items on the stack to do an FP conversion, so if you push six items, you should be okay (actually, you can push seven, because your code pops one item off before calling stdout.put).
Cheers,
Randy Hyde
Posted on 2004-03-05 16:29:25 by rhyde
randall

Not being at all familiar with the HLL instructions of HLA, I picked the wrong one to explain the "nasty" :o surprise. That's why I strongly believe in my signature.

Thanks for clearing up which one was at fault in this case. (BTW are users made aware of this potential problem in HLA's Help files?)

Raymond
Posted on 2004-03-06 00:23:00 by Raymond

randall

Not being at all familiar with the HLL instructions of HLA, I picked the wrong one to explain the "nasty" :o surprise. That's why I strongly believe in my signature.

Thanks for clearing up which one was at fault in this case. (BTW are users made aware of this potential problem in HLA's Help files?)

Raymond


Of course :-).
The extensions to the instruction set are always pointed out as being extensions. And the documentation certainly explains how the extensions are implemented.
Cheers,
Randy Hyde
Posted on 2004-03-06 15:21:12 by rhyde
Thanks for that clarification. However, IMHO, to assume that users will notice, absorb and apply such information will probably be correct much less than half the time.

This acts as a reminder for me to modify (as soon as I can) my library of FPU functions (Fpulib) to simply avoid such nasty surprises by saving and restoring any FPU register which would be required to be emptied to perform the called function. You may want to consider similar action with your HLL instructions using the FPU.

With all due respect for your immense contributions,

Raymond
Posted on 2004-03-06 23:06:22 by Raymond
Many thanks for clearing that up, Raymond and Randall Hyde.

Btw, I have +/- 5 other small questions, but I'll mail them all at once in a single thread, soon. And if you guys could take the time and trouble to, once, again come to my aid I would be forever in your debt.

Dear Mr Hyde,

I'm still using the beta version so I don't know if you've already updated AoA. But I also think it would be very helpful (from a student's point of view) if you could also make note/warn about the possible oversight when attempting to use all 8 registers in HLA.

Everything of the best, with the WinXP programming, Raymond!

My most grateful and warmest thanks.
Posted on 2004-03-08 01:12:08 by Jaysen

Dear Mr Hyde,

I'm still using the beta version so I don't know if you've already updated AoA. But I also think it would be very helpful (from a student's point of view) if you could also make note/warn about the possible oversight when attempting to use all 8 registers in HLA.

Everything of the best, with the WinXP programming, Raymond!

My most grateful and warmest thanks.


Actually, the "final" edition is the published edition by No Starch Press. And in Chapter One I explicitly state "The SP/ESP register pair, for example, has a very special purpose that effectively prevents you from using it for any other purpose..." I don't fully explain the problems at this point in the book (it is Chapter One, after all), but I do mention that ESP is, effectively, unusable.
Cheers,
Randy Hyde
Posted on 2004-03-08 14:24:15 by rhyde
jaysen,

if you are using windows then i highly recommend downloading ollydebug; its free, its pretty and its very useful.

debugging is time consuming, confusing, and soul destroying, ollydebug takes the edge off it.

if you were using it then i'm sure you would have been able to work out what went wrong with your program.

anyway, continued good luck to you sir,
fatray.
Posted on 2004-03-09 20:42:15 by fatray
Thanks Fatray,

I'm going to download OllyDebug now...

Kindest regards.
Posted on 2004-03-15 06:22:31 by Jaysen