Answers:
它测试是否eax
为0或更高或更低。在这种情况下,如果eax
为0 ,则进行跳转。
test
和之间的标记完全相同cmp
。是的,我了解您的信念是基于您对科迪的评论。但是,将其放在我的帖子中是另一回事。这不是我愿意坚持的主张,仅仅是因为我不知道在所有情况下它是否相同。
je
,jz
,cmp
,和test
,而不是JE,JZ,CMP或TEST。我很挑剔
test a,a
并cmp $0,a
设置相同的标志。感谢您指出这是不平凡的主张。re:TEST vs . test
:最近,我开始使用像Intel手册这样的全大写字母。但是,当我谈论AT&T助记符与Intel助记符时,我testb
对AT&T 使用样式。IDK是否有助于提高可读性。
测试指令在操作数之间进行逻辑“与”运算,但不会将结果写回到寄存器中。仅标志被更新。
在您的示例测试eax中,如果eax为零,则eax将设置零标志,如果设置了最高位,则将设置符号标志,以及其他一些标志。
如果设置了零标志,则跳转相等指令(je)。
您可以将代码转换为更具可读性的代码,如下所示:
cmp eax, 0
je somewhere
它具有相同的功能,但需要更多字节的代码空间。这就是为什么编译器发出测试而不是比较的原因。
test eax, eax
并cmp eax, 0
都设置所有标志,并将它们设置为相同的值。两条指令均“根据结果”设置所有标志。减法0
永远不会产生进位或溢出。你的论点比0任何其他即时正确的,但不能为0
test
类似于and
,只是它只写FLAGS,而两个输入都保持不变。对于两个不同的输入,这对于测试某些位是否全部为零或是否设置了至少一个很有用。(例如,test al, 3
如果EAX为4的倍数,则设置ZF(因此将其低2位都清零)。
test eax,eax
将所有的标志正是以同样的方式cmp eax, 0
将:
a = a&a = a-0
)。除了过时的AF(辅助进位标志,由ASCII / BCD指令使用)。 TEST使它保持未定义状态,但是CMP会“根据结果”对其进行设置。由于减零不能从第4位到第5位产生进位,因此CMP应始终清除AF。
TEST较小(不立即),有时更快(可以比CMP在更多情况下将其宏融合到更多CPU上的“比较分支” uop中)。 这就是test
比较寄存器与零的首选惯用法。这是一个窥视孔优化,cmp reg,0
无论语义如何,都可以使用。
使用立即数CMP的唯一常见原因是要与内存操作数进行比较。例如,cmpb $0, (%esi)
在隐式长度的C样式字符串的末尾检查终止的零字节。
AVX512F加法kortestw k1, k2
和AVX512DQ / BW(Skylake-X但不支持KNL)加法ktestb/w/d/q k1, k2
,它们对AVX512掩码寄存器(k0..k7)进行操作,但仍像设置test
整数OR
或AND
指令一样设置常规FLAGS 。(类似于SSE4 ptest
或SSE的排序ucomiss
:在SIMD域中输入,并产生整数FLAGS。)
kortestw k1,k1
是根据AVX512比较结果来分支/ cmovcc / setcc的惯用方式,取代了SSE / AVX2 (v)pmovmskb/ps/pd
+ test
或cmp
。
jz
vs.的使用je
可能会造成混淆。
jz
并且je
实际上是相同的指令,即机器代码中的相同操作码。 它们做同样的事情,但是对人类有不同的语义。反汇编程序(通常是编译器的asm输出)只会使用一个,因此会失去语义上的区别。
cmp
和sub
设置ZF当其两个输入是相等的(即,相减结果为0)。 je
(如果相等则跳转)是语义相关的同义词。
test %eax,%eax
/ and %eax,%eax
在结果为零时再次设置ZF,但是没有“平等”测试。测试后的ZF不会告诉您两个操作数是否相等。因此jz
(如果为零则跳转)是语义上相关的同义词。
test
按位and
操作的基本信息,这对于刚刚学习汇编的人来说可能并不明显(并且懒惰/不知道每60秒检查一次指令参考指南;):))。
kortest*
,ktest*
而我当时还在。
此代码段来自一个子例程,该子例程被赋予了指向某些内容(可能是某些结构或对象)的指针。第二行取消对该指针的引用,从该东西中获取一个值-可能本身就是一个指针,或者可能只是一个int,存储为第二个成员(偏移+4)。第三行和第四行将该值测试为零(如果是指针,则为NULL),如果该值为零,则跳过以下几个操作(未显示)。
零测试有时被编码为与立即数立即值零的比较,但是编写此代码的编译器(或人类?)可能认为testl op运行得更快-考虑到所有现代CPU的东西,例如流水线和寄存器重命名。它来自同一堆花样,其中包含用XOR EAX,EAX(我在科罗拉多州某人的车牌上看到的!)清除寄存器的想法,而不是明显但较慢的MOV EAX#0(我使用的是较旧的表示法) )。
在asm中,就像perl一样,TMTOWTDI。
在某些程序中,它们可用于检查缓冲区溢出。在分配的空间的最顶部放置一个0。将数据输入堆栈后,它将在分配的空间的开头查找0,以确保分配的空间不会溢出。
在exploits-exercises的stack0练习中使用它来检查它是否溢出,如果没有,并且那里为零,它将显示“再试一次”。
0x080483f4 <main+0>: push ebp
0x080483f5 <main+1>: mov ebp,esp
0x080483f7 <main+3>: and esp,0xfffffff0
0x080483fa <main+6>: sub esp,0x60
0x080483fd <main+9>: mov DWORD PTR [esp+0x5c],0x0 ;puts a zero on stack
0x08048405 <main+17>: lea eax,[esp+0x1c]
0x08048409 <main+21>: mov DWORD PTR [esp],eax
0x0804840c <main+24>: call 0x804830c <gets@plt>
0x08048411 <main+29>: mov eax,DWORD PTR [esp+0x5c]
0x08048415 <main+33>: test eax,eax ; checks if its zero
0x08048417 <main+35>: je 0x8048427 <main+51>
0x08048419 <main+37>: mov DWORD PTR [esp],0x8048500
0x08048420 <main+44>: call 0x804832c <puts@plt>
0x08048425 <main+49>: jmp 0x8048433 <main+63>
0x08048427 <main+51>: mov DWORD PTR [esp],0x8048529
0x0804842e <main+58>: call 0x804832c <puts@plt>
0x08048433 <main+63>: leave
0x08048434 <main+64>: ret
cmp DWORD PTR [esp+0x5c], 0
/ jz 0x8048427 <main+51>
会比单独的MOV加载和TEST更有效。这几乎不是检查零的常见用例。