除了在 cmp $0 上保存大小之外的测试用途

sam*_*249 1 x86 assembly

我想知道如何cmp在对寄存器进行零检查时保存一个字节之外如何使用,例如:

cmp $0, %eax
Run Code Online (Sandbox Code Playgroud)

对比

test %eax, %eax
Run Code Online (Sandbox Code Playgroud)

我正在做一些反复试验,这似乎是它的主要用途(除非我遗漏了一些东西——如果任何进一步的用法可以使用该and指令)。

test指令还有其他用途吗?


有点相关:在 x86 中, "test eax,eax" 和 "cmp eax,0" 之间有什么区别


以下是我做的一些示例:

   mov $1, %eax
   mov $2, %ebx
   test %eax, %ebx
   jg _start       # <-- doesn't jump
   jl _start       # <-- doesn't jump

   mov $1, %eax
   mov $1, %ebx
   test %eax, %ebx
   je _start       # <-- doesn't jump

   mov $0, %eax
   mov $1, %ebx
   test %eax, %ebx
   je _start       # <-- why is this the only one that works? 1 & 0 == 0 ?
Run Code Online (Sandbox Code Playgroud)

Bre*_*dan 5

test指令还有其他用途吗?

test指令的用途包括:

  • 检查值是否为零。例如if(x == 0)->test eax,eax

  • 检查一个值是否可以被 2 的任何幂整除。例如if(x % 8 == 0)->test eax,7

  • 检查特定位/秒。例如if(x & (S_IREAD | S_IWRITE) == 0)-> test eax,(S_IREAD | S_IWRITE)。注意:这可能是“主要用途”。

  • 将 2 个或更多个较小值打包在一起的各种情况。例如,如果您将两个有符号的 16 位值打包到 EAX 中,那么您test eax,0x80008000可以确定这两个 16 位值中的任何一个是否为负;如果您应该将四个 ASCII 字符打包到 EAX 中,您test eax,0x80808080可以确定它们是否都是有效的 ASCII;如果您将三个 10 位数字装入 EAX 并想检查它们是否都小于 512,则可以test eax,(0x200 << 20) | (0x200 << 10) | 0x200 ;如果您将六个 5 位值打包到 EAX 中,并且想要检查第二个值是否大于 8,您可以test eax, (0x18 << 6)。当然,这可以扩展为使用更多寄存器(例如,将 16 个 6 位值打包到 EDX:EBX:EAX 中并使用三个test指令来……)和/或用其他指令扩充(例如,可能nottest)。注意:这些情况对单个值的作用相同,但对于单个值(主要是cmp)有更好/更简单的替代方案,主要好处是避免需要解包。

以下是我做的一些示例:

有多个标志(CF/进位、OF/溢出、SF/符号、ZF/零、AF/辅助、PF/奇偶校验)和不同的“ Jcc”条件分支使用不同的标志(例如jc使用 CF、js使用 SF 等)。所有“按位”指令(AND、OR、XOR、TEST)清除 CF 和 OF 并使 AF 未定义,因此任何依赖于这些标志的条件分支都没有意义(例如jl依赖于 SF 和 OF 但 OF 总是清除test,因此jl在 之后没有意义test)。

您的第二个示例有效但不应该跳转(就像“ if(1 & 1 == 0) goto __start;”一样什么都不做)。您的第三个示例有效并且应该跳转。