5

我一直在努力解决这个问题,这对我来说毫无意义......

为什么这个程序会进入死循环?!

我想你可以用它来比较两个值是否相等,如此test所示......为什么它不起作用?

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

3 回答 3

7

你对TEST指令的期望是不正确的。

该指令用于执行位测试。如果某些位设置为给定掩码,您通常会使用它来“测试”。它将与JZ(jump if zero) 或JNZ(jump if not zero) 指令结合使用。

该测试涉及对两个操作数执行按位与并设置适当的标志(丢弃结果)。如果没有设置掩码中的相应位,则 ZF(零标志)将为1(所有位为零)。如果您想测试是否设置了任何设置,您将使用该JNZ指令。如果你想测试是否没有设置,你会使用JZ指令。

JEJNE不适用于该指令,因为它们对标志的解释不同。


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

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


在这种情况下,由于您使用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
    }
}
于 2013-03-03T04:36:55.663 回答
3

只是读这个(我的 asm 很生锈)和这个

JNE 跳到 ZF(零标志)= 0

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

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

因此它在 ZF 中跳跃为 1 AND 1 结果为 0。

似乎合乎逻辑但反直觉。

我认为@A.Webb 是正确的-如果您使用 TEST 指令,它可能应该是 JNZ,因为您依赖 bitwuse 操作的行为来设置零标志,而 SUB 指令会根据需要设置零标志.

于 2013-03-03T04:09:01.433 回答
1

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

您的具体程序:

    mov EAX, 1;

将常数 1 移动到 EAX。不会发生其他状态更改。

    mov EDX, EAX;

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

    test EAX, EDX;

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

 L:      jne L;

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

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

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

于 2013-03-03T04:42:59.440 回答