x86保留EFLAGS位1 == 0:这怎么可能发生?

时间:2014-04-01 05:44:35

标签: multithreading winapi state eflags

我使用Win32 API停止/启动/检查/ 更改线程状态。一般工作得很好。有时它失败了,我试图追查原因。

我有一个线程强制通过以下方式在其他线程上进行上下文切换:

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

这非常好用......但......很少,上下文切换似乎失败了。 (症状:我的多线程系统在执行奇怪的寄存器内容的奇怪地方时高高飘扬。)

上下文控制由以下人员完成:

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");
        ...
   }

没有任何打印语句被执行。我得出结论,Windows认为上下文操作都是可靠的。

哦,是的,我知道何时停止的线程不计算 [例如,在系统功能中]并且不会尝试停止/上下文切换它。我知道这一点,因为每个执行除计算之外的任何事情的线程都会设置一个特定的线程,而不是触摸我。标志,虽然它正在进行非计算。 (设备驱动程序程序员会将此识别为&#34;中断禁用&#34;指令)。

所以,我想知道上下文块内容的可靠性。 我在上下文块中提取的各种寄存器值上添加了各种健全性测试;你实际上可以确定ESP是正常的(在TIB中定义的堆栈区域的范围内),PC在我期望的程序中或在系统调用中等等。这里没什么惊喜。

我决定检查条件代码位(EFLAGS)是否被正确读出;如果这是错误的,它将导致切换任务采取错误的分支&#34;当它的状态是 恢复。因此,我添加了以下代码,以验证所声称的EFLAGS寄存器包含的内容仅根据英特尔参考手册(http://en.wikipedia.org/wiki/FLAGS_register)看起来像EFLAGS。

   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
@@:

在我的Win 7 AMD Phenom II X6 1090T(hex core)上, 它会偶尔陷入断点,ECX = 0200h。在我的Win 7 Intel i7系统上失败。我会忽略这一点, 除非它暗示EFLAGS没有正确存储,我怀疑。

根据我对英特尔(以及AMD)参考手册的阅读,第1位是保留的,并且始终具有值&#34; 1&#34;。不是我在这里看到的。

显然,MS通过在线程停止上执行复杂的操作来填充上下文块。我希望他们准确地存储状态。该位未正确存储。 如果他们没有正确存储这一点,他们还有什么不存储?

为什么这个位的值有时/应该为零的任何解释?

编辑:我的代码在捕获断点时转储寄存器和堆栈。 堆栈区域包含上下文块作为局部变量。 EAX和上下文块中EFLAGS的适当偏移量中的堆栈中的值都包含值0244h。所以上下文块中的值确实是错误的。

EDIT2:我将掩码和比较值更改为

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

这似乎可靠地运行而没有任何抱怨。显然,Win7并没有正确地做出第1位的eflags,看起来并不重要。

仍然对解释感兴趣,但显然这不是我偶尔上下文切换崩溃的原因。

1 个答案:

答案 0 :(得分:0)

微软有着悠久的历史,在没有真正使用过的地方徘徊一些。 Raymond Chen给出了很多例子,例如使用非字节对齐的指针的低位。

在这种情况下,Windows可能需要在现有CONTEXT结构中存储其某些线程上下文,并决定使用EFLAGS中未使用的位。无论如何你都无法做任何事情,当你拨打SetThreadContext时,Windows会回来。