I have recently observed that some of the API functions under Windows XP seem to be using MMX or other similar instructions without saving the state of the FPU and restoring it prior to leaving.

This may result in the trashing of any data remaining in the FPU registers if those API functions are called while using the FPU. I have sent the following note to Microsoft and will keep this board informed if I ever get any feedback.
I have recently observed a potential major problem with Windows XP (Home Edition). It would seem that MMX or other instructions using the FPU registers have been used in some of the API functions without the decency of preserving the content of the FPU and restoring it before leaving the function.

You can verify the above by loading a few registers with floating point data before calling the CreateWindowEx and ShowWindow functions, and inspecting the content of the FPU registers before and after the calls.

This makes it impossible to trust any of the other API functions to preserve the FPU environment and thus force programmers to save and restore such environment if API functions need to be called while using the FPU for floating point computations under Windows XP.

This may not be realized by most programmers before many applications are written with the potential of producing erratic results.


Raymond
Posted on 2003-08-10 09:29:39 by Raymond
Oops :grin:
Posted on 2003-08-10 09:41:04 by Delight
Can you repoduce this in a language other than assembly (e.g. C++, preferably
using a M$ compiler)? Otherwise it might be an undocumented feature ;)
Posted on 2003-08-10 10:24:11 by Tola
Unfortunately, I am not very familiar with C/C++ (I do not have to earn a living with programming).

If you are allowed to leave floating point data on the FPU by doing some partial computation in C/C++, you can test it by doing it before you call the CreateWindowEx function and then continue the computation and display the result.

Some function(s) used by CreateWindowEx under WinXP also seem to use the FPU to perform computations (which could probably be performed with integer maths) and requiring at least 3 registers. If you preload at least 6 of the 8 data registers, an invalid operation and stack overflow exceptions get recorded. The function recovers by freeing the required register(s) to accomplish its objective and returns with 3 free registers but without clearing the exceptions.

Raymond
Posted on 2003-08-10 11:40:59 by Raymond
Here's a test:
void CreateWindow(HINSTANCE hInstance, int nCmdShow)

{
float f = static_cast<float>(GetTickCount());
float b = f * f + 4.0f;
HWND hWnd = CreateWindowEx(NULL, szWindowClass, szTitle,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0, NULL, NULL, hInstance,
NULL);
float c = b * 2.0f;
printf("b = %f, c = %f", b, c);
}

The compiler did not assume CreateWindowEx would preserve the FPU state, it loads the stored value of b from the local stack memory again after the call, as you can see from the disassembly below..

I never assumed API's preserved the FPU anyway... I don't think it's a bug that they aren't preserved in some cases, it's just the way it is.

Thomas
Posted on 2003-08-10 12:02:48 by Thomas
I just played around a bit with two different compilers (MS and Intel),
both of them stored any used floating point variables on the stack
before calling CreateWindowEx.
Posted on 2003-08-10 12:05:31 by Tola
Under Win98SE, the CreateWindowEx function does not make any use at all of the FPU hardware.

I wonder if C/C++ compilers from that era were also preserving FPU data on the stack prior to API calls, or has that feature been added more recently.

Raymond
Posted on 2003-08-10 12:23:45 by Raymond
Thanks for the info :alright:
But, this just confirms me that MS uses its C compiler to construct API.

C functions have serveral rules about register state.
1. ebx,esi,edi,ebp are preserved and other general purpose registers are trashed.
2. fpu resister stack is empty before the function entry and empty after return, unless the function returns float or double result, in which case the return value is in st(0).

And, xmm registers are unknown to C compilers and no known compilers except Intel's uses it (yet).

If you have been ignoring the second rule and had no problem, you were simply lucky. Remeber that the machine language is not the primary building block of windows.

Oh, BTW, the above rule is fairly universal across x86 C (32 bit) compilers. If any of you work on non-windows platforms, the above rules should be kept in mind.


Another thing. The above is well-documented (otherwise how would I know? ;) ) but I forgot the URL. You should be able to find the link searching for something like asm function for C or using C fuction from asm. The point is, it is not API's problem. All C functions share the same rule.
Posted on 2003-08-10 15:34:30 by Starless