【问题标题】:x86 TEST instruction not working?x86 TEST 指令不起作用?
【发布时间】:2013-03-03 03:51:49
【问题描述】:

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

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

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

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

【问题讨论】:

  • 这是 Intel 还是 AT&T 语法?
  • @Mysticial:我不认为mov EAX, 1 可以是AT&T 语法,可以吗? :)
  • 哦,你是对的。无论如何,这并不重要。因为EDX == EAX不管。 :)
  • @Mysticial:是啊,哈哈。
  • 你能展示一下实际的反汇编吗?

标签: c assembly x86


【解决方案1】:

您对TEST 指令所做的预期不正确。

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

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

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


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

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


在这种情况下,由于您使用了TEST,因此生成的标志将产生ZF = 0(0x1 & 0x1 = 0x1,非零)。由于ZF = 0JNE 指令将采用您在此处看到的分支。

tl;博士

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

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

【讨论】:

  • +1 太棒了,感谢您的解释。我认为test 可用于测试相等性(我想我希望它比cmp 更快,因为它不检查排序)但我想不是。
  • Test 可用于检查寄存器是否“等于零”(或不等于),方法是将其应用于与两个操作数相同的寄存器。您还可以通过使一个操作数保持不变(全为一位)来测试零。您可以通过选择适当的寄存器来测试各种宽度 8、16、32、64 的零;在评论中解释这一切都很混乱。
【解决方案2】:

只是阅读this(我的asm 很生锈)和this

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 指令将设置零标志根据需要。

【讨论】:

  • +1 哇,这太令人困惑了。那为什么我看到的每段代码都使用jejne?这些都不行吗?
  • @Mehrdad jzje 是同义词,使用 jz 可使意图对人类更加清晰。编译器生成的反汇编器和汇编列表似乎更喜欢je 变体(我不知道为什么,我想这并不重要)
【解决方案3】:

这很简单。您显然需要知道指令的作用,它们读取和写入的处理器状态。如有疑问,请获取参考手册。 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 位被重置,它就会跳转。对于您的程序,Z 被重置,jmp 发生。执行后,处理器处于相同的指令,并看到另一个指令(相同的 jmp)。 jmp 指令不会更改条件代码位。

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

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

【讨论】:

    猜你喜欢
    • 2019-04-20
    • 2018-03-12
    • 1970-01-01
    • 2020-01-05
    • 2017-12-06
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多