X86 reserved by EFLAGS bit 1 == 0: how can this happen?

I use the Win32 API to stop / start / check / change the state of a stream. Usually works very well. Sometimes he fails and I try to find the reason.

I have one thread that forces context switches to other threads:

thread stop fetch processor state into windows context block read thread registers from windows context block to my own context block write thread registers from another context block into windows context block restart thread 

This works remarkably well .... but ... very rarely, context switches seem to fail. (Symptom: my multi-threaded system knocks down the sky, performing strange places with strange register contents).

Contextual management is performed using:

 if ((suspend_count=SuspendThread(WindowsThreadHandle))<0) { printf("TimeSlicer Suspend Thread failure"); ... } ... Context.ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_FLOATING_POINT); if (!GetThreadContext(WindowsThreadHandle,&Context)) { printf("Context fetch failure"); ... } call ContextSwap(&Context); // does the context swap if (ResumeThread(WindowsThreadHandle)<0) { printf("Thread resume failure"); ... } 

None of the print statements are ever executed. I came to the conclusion that Windows believes that all context operations are performed reliably.

Oh, yes, I know when a stopped thread does not calculate [for example, in a system function] and does not try to stop / the context switches it. I know this because every thread that does something other than computation sets up a specific thread "not touching me" while it does other computations. (Device driver programmers recognize this as the equivalent of disabling interrupt instructions).

So, I wondered about the reliability of the contents of the context block. I have added many sanity tests for various register values ​​pulled from the context block; you can actually decide that the ESP is OK (within the stack area defined in the TIB), the PC is in the expected program or in a system call, etc. There are no surprises here.

I decided to check the readability of the status code bits (EFLAGS); if it were wrong, it would cause the switched task to take the "wrong branch" when its state was restored. So I added the following code to verify that the declared EFLAGS register contains material that only looks like EFLAGS according to the Intel reference guide ( http://en.wikipedia.org/wiki/FLAGS_register ).

  mov eax, Context.EFlags[ebx] ; ebx points to Windows Context block mov ecx, eax ; check that we seem to have flag bits and ecx, 0FFFEF32Ah ; where we expect constant flag bits to be cmp ecx, 000000202h ; expected state of constant flag bits je @f breakpoint ; trap if unexpected flag bit status @@: 

On my Win 7 AMD Phenom II X6 1090T (hexadecimal kernel), it periodically traps with a breakpoint, with ECX = 0200h. Does not work the same on my Win 7 Intel i7. I would ignore this, except for hints that EFLAGS are stored incorrectly, as I suspected.

According to my reading of Intel (as well as AMD) directories, bit 1 is reserved and always has a value of "1". Not what I see here.

Obviously, MS fills the context block, doing complex things when the thread stops. I expect that they will definitely keep the state. This bit is not stored correctly. If they do not save this bit correctly, what else do they not save?

Any explanation why the value of this bit could / should be zero?

EDIT: my code flushes registers and stack when a breakpoint is detected. The stack area contains the context block as a local variable. Both EAX and the stack value with the correct offset for EFLAGS in the context block contain the value 0244h. So the value in the context block is really wrong.

EDIT2: I changed the mask and companion values ​​to

  and ecx, 0FFFEF328h ; was FFEF32Ah where we expect flag bits to be cmp ecx, 000000200h 

This seems to work reliably without any complaints. Obviously, Win7 does not make bit 1 of eflags to the right, and it does not seem to matter.

Still interested in the explanation, but it is not the source of my accidental context switch failure.

+7
multithreading winapi state eflags
source share
1 answer

Microsoft has a long history of crossing several bits in places that are not actually used. Raymond Chen gave many examples, for example. using the bottom bit (s) of a pointer that is not byte aligned.

In this case, Windows might need to keep some thread context in the existing CONTEXT structure and decide to use another unused bit in EFLAGS . You still could not do anything with this bit, and Windows will get that bit back when you call SetThreadContext .

0
source share

All Articles