x86 TEST指令不起作用?

时间:2013-03-03 03:51:49

标签: c assembly x86

我一直在撞墙撞墙,这对我来说毫无意义......

为什么这个程序进入无限循环?!

我认为您可以使用test来比较两个值的相等性,如here所示......为什么不起作用?

int main()
{
    __asm
    {
        mov EAX, 1;
        mov EDX, EAX;
        test EAX, EDX;
L:      jne L;
    }
}

3 个答案:

答案 0 :(得分:7)

您对TEST指令执行操作的期望不正确。

该指令用于执行位测试。您通常会使用它来“测试”是否在给定掩码的情况下设置某些位。它将与JZ(如果为零则跳转)或JNZ(如果不为零则跳转)指令一起使用。

测试涉及对两个操作数执行按位AND,并设置适当的标志(丢弃结果)。如果掩码中没有相应的位被置位,那么ZF(零标志)将是1(所有位都为零)。如果您想测试是否已设置,则使用JNZ指令。如果您想测试是否未设置,则使用JZ指令。

JEJNE不适合此指令,因为它们会以不同方式解释标记。


您正尝试对某些变量执行相等检查。您应该使用CMP指令。您通常会使用它来相互比较值。

比较有效地减去操作数并仅设置标志(丢弃结果)。当相等时,两个值的差值为0(ZF = 1)。当不相等时,两个值的差值为非零(ZF = 0)。如果你想测试它们是否相等,你可以使用JE(如果相等则跳转)指令。如果你想测试它们是否不相等,你可以使用JNE(如果不相等则跳转)指令。


在这种情况下,由于您使用了TEST,结果标志将产生ZF = 0(0x1& 0x1 = 0x1,非零)。从ZF = 0开始,JNE指令将按照您在此处看到的那样执行分支。

TL;博士

如果要检查是否相等,则需要使用CMP指令比较值,而不是TEST

int main()
{
    __asm
    {
        mov EAX, 1
        mov EDX, EAX
        cmp EAX, EDX
L:      jne L          ; no more infinite loop
    }
}

答案 1 :(得分:3)

阅读this(我的asm非常生疏)和this

JNE跳转到ZF(零标志)= 0

TEST设置ZF = 0 如果按位EAX AND EDX导致1 ,如果按位AND则导致0

  

如果AND的结果为0,则ZF设置为1,否则设置为   0

因此它跳转为1和1在ZF中导致0。

似乎逻辑但反直觉。

我认为@ A.Webb是对的 - 如果您使用TEST指令,它可能应该是JNZ,因为您依靠bitwuse操作的行为来设置零标志,而SUB指令将设置Zero标志如你所知。

答案 2 :(得分:1)

这很简单。您显然需要知道指令的作用,读取的处理器状态以及写入。如有疑问,请参阅参考手册。英特尔x86手册很容易在网上找到。

您的具体计划:

    mov EAX, 1;

将常量1移动到EAX。没有其他状态发生变化。

    mov EDX, EAX;

将EAX的上下文复制到EDX中,因此它也包含值1。

    test EAX, EDX;

test计算两个寄存器的按位AND(你检查参考手册吗?),抛出答案,并根据答案设置条件代码位。在您的情况下,每个寄存器的高31位为零,并生成零。最低有效位是两个寄存器中的一个;并且产生1.净效果是生成32二进制值“1”,并在设置条件代码位后丢弃。我们关心这个程序有一个条件代码位,那就是“Z”(ero)位,如果最后一个条件代码设置操作产生一个完整的零值,则设置该位。该测试产生“1”,因此Z位被复位。我会让你查看其他条件代码位。

 L:      jne L;

这是“Jmp on Not Equal”,例如,如果Z位复位则jmps。对于您的程序,Z被重置,jmp发生。执行后,处理器处于相同的状态,并看到另一个(相同的jmp)。条件代码位不会被jmp指令改变。

所以......它进入了一个无限循环。

汇编程序支持的各种操作码有很多同义词。例如,“JZ”和“JE”是同一指令的同义词。不要让同义词混淆。