`testl` eax反对eax?

我想了解一些程序集。

大会如下,我对testl行感兴趣:

 000319df 8b4508 movl 0x08(%ebp), %eax 000319e2 8b4004 movl 0x04(%eax), %eax 000319e5 85c0 testl %eax, %eax 000319e7 7407 je 0x000319f0 

我想了解%eax%eax之间的testl点吗? 我认为这个代码的重要性并不重要,我只是试图用自己来理解testing – 这个价值永远不会是真的吗?

它testingeax是否为0或更高或更低。 在这种情况下,如果eax为0,则跳转。

test的意义是将参数与参数一起,并检查结果为零。 所以这个代码testingEAX是否为零。 如果零, je会跳。

顺便说一下,这会产生一个比cmp eax, 0更小的指令cmp eax, 0这就是编译器通常这样做的原因。

testing指令在操作数之间进行逻辑与操作,但不将结果写回寄存器。 只有标志被更新。

在你的例子中,testingeax,如果eax为零,eax将设置零标志,如果设置了最高位,则标志标志也会置位。

如果等于(je)指令跳转,如果零标志被设置。

您可以将代码翻译成更可读的代码,如下所示:

 cmp eax, 0 je somewhere 

这有相同的function,但需要一些字节更多的代码空间。 这就是为什么编译器发出testing而不是比较的原因。

test eax,eax设置所有标志完全一样cmp eax, 0会:

  • CF和OF清零(AND / TEST总是这样做,而减零不会产生进位)
  • ZF,SF和PF根据EAX中的值。 ( a = a&a = a-0

(除了过时AF(辅助进位标志,由ASCII / BCD指令使用)之外, TEST不定义 ,但CMP根据结果设置它 。由于减零不能产生从第4个到第5个进位CMP应该始终清除AF)。


TEST更小(不立即),有时更快(可以在比CMP更多的情况下在更多的CPU上将macros观融入到比较分支的uop中)。 这使得test成为testing寄存器为零或不是零的首选成语 。

使用立即为0的CMP的唯一常见原因是当你想要比较一个内存操作数(例如, cmpb $0, (%esi)来检查一个隐式长度的C风格末尾的终止零字节串)。


jzje可能会jz困惑。

jzje字面上是相同的指令 ,即机器码中的相同操作码。 他们做同样的事情,但对人类有不同的语义 。 反汇编程序(通常是编译器的输出)只会使用一个,所以语义上的差别就会丢失。

当它们的两个input相等时(即,相减结果是0), cmpsub集ZF。 je (如果相等则跳转)是语义上相关的同义词。

test %eax,%eax / and %eax,%eax在结果为零时再次设置ZF,但是没有“相等”testing。 ZF经过testing并没有告诉你这两个操作数是否相等。 所以jz (跳转,如果是零)是语义相关的同义词。

这段代码来自一个被指定了某个东西的子程序,可能是一些结构或对象。 第二行取消引用这个指针,从它的第二个成员(偏移+4)中获取一个值 – 可能是一个指针或者可能只是一个int值。 第三行和第四行testing这个值为零(如果它是一个指针,则为NULL),如果它为零,则跳过下面的几个操作(未示出)。

有时零的testing被编码为立即文字零值的比较,但编译器(或人类)写这个可能会认为testl运行速度会更快 – 考虑到所有现代CPU的东西,如stream水线和注册重命名。 这是从同一个包装的技巧,拥有与XOR EAX,EAX(我在科罗拉多州的人的车牌上看到)清除registry的想法,而不是显而易见的,但也许更慢的MOV EAX,#0(我使用一个更旧的表示法)。

在asm中,像perl,TMTOWTDI。

如果eax为零,它将执行条件跳转,否则它将在319e9继续执行

在某些程序中,它们可以用来检查缓冲区溢出。 在分配空间的最顶端放置一个0。 将数据input到堆栈后,会在分配空间的最开始处查找0,以确保分配的空间不会溢出。

它被用在stack0的exploit-exercise练习中,以检查它是否溢出,如果没有,那里有一个零,它会显示“Try again”

 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 

我们可以看到jgjle如果testl testl %edx,%edx. jle .L3 如果%edx为零,则ZF = 1,但是如果%edx不为零并且为-1,则在testl之后,OF = 0,并且SF = 1,所以flag = true,实现跳跃。不过,我的英文很差