`testl` eax 与 eax 对比?
-
02-07-2019 - |
题
我试图理解一些组装。
组装如下,我感兴趣的是 testl
线:
000319df 8b4508 movl 0x08(%ebp), %eax
000319e2 8b4004 movl 0x04(%eax), %eax
000319e5 85c0 testl %eax, %eax
000319e7 7407 je 0x000319f0
我试图理解这一点 testl
之间 %eax
和 %eax
?我认为这段代码的细节并不重要,我只是想理解测试本身 - 该值不总是正确的吗?
解决方案
它测试是否 eax
为 0、或高于、或低于。在这种情况下,如果 eax
是 0。
其他提示
的含义 test
是将参数与在一起,并检查结果是否为零。所以这段代码测试 EAX 是否为零。 je
如果为零则跳转。
顺便说一句,这生成的指令比 cmp eax, 0
这就是编译器通常会这样做的原因。
测试指令在操作数之间执行逻辑与运算,但不会将结果写回到寄存器中。仅更新标志。
在您的示例中,测试 eax,如果 eax 为零,则 eax 将设置零标志,如果设置了最高位,则 eax 将设置符号标志以及其他一些标志。
如果设置了零标志,则跳转(je)指令将跳转。
您可以将代码转换为更具可读性的代码,如下所示:
cmp eax, 0
je somewhere
它具有相同的功能,但需要更多字节的代码空间。这就是编译器发出测试而不是比较的原因。
test
就好像 and
, ,但它只写入 FLAGS,而其两个输入均未修改。与两个 不同的 输入,它对于测试某些位是否全为零或是否至少设置了一个很有用。(例如。 test al, 3
如果 EAX 是 4 的倍数(因此其低 2 位均为零),则设置 ZF。
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 上宏融合到比较和分支微指令中)。 这使得 test
测试寄存器是否为零的首选习惯用法.
将 CMP 与立即数 0 一起使用的唯一常见原因是当您想要与内存操作数进行比较时(例如, cmpb $0, (%esi)
检查隐式长度 C 样式字符串末尾是否有终止零字节)。
AVX512F 添加 kortestw k1, k2
和 AVX512DQ/BW(Skylake 但不是 KNL)添加 ktestb/w/d/q k1, k2
, ,它在 AVX512 掩码寄存器 (k0..k7) 上运行,但仍然设置常规标志,例如 test
和整数一样 OR
或者 AND
指示做。
kortestw k1,k1
是基于 AVX512 比较结果分支 / cmovcc / setcc 的惯用方法,替换 SSE/AVX2 (v)pmovmskb/ps/pd
+ test
或者 cmp
.
用于 jz
与 je
可能会令人困惑。
jz
和 je
实际上是相同的指令, , IE。机器码中的操作码相同。 它们做同样的事情,但对人类来说具有不同的语义意义. 。反汇编器(通常是编译器的 asm 输出)只会使用一个,因此语义区别就会丢失。
cmp
和 sub
当两个输入相等时设置 ZF(即减法结果为0)。 je
(如果相等则跳转)是语义相关的同义词。
test %eax,%eax
/ and %eax,%eax
当结果为零时再次设置 ZF,但没有“相等”测试。测试后的 ZF 不会告诉您两个操作数是否相等。所以 jz
(如果为零则跳转)是语义相关的同义词。
这段代码来自一个子例程,该子例程被赋予了一个指向某个东西的指针,可能是某个结构或对象。第二行取消引用该指针,从该指针获取一个值 - 可能本身是一个指针,也可能只是一个 int,存储为其第二个成员(偏移量 +4)。第 3 行和第 4 行测试该值是否为零(如果它是指针,则为 NULL),如果它为零,则跳过以下几个操作(未显示)。
对零的测试有时被编码为与立即文字零值的比较,但编写此代码的编译器(或人类?)可能认为 testl 操作会运行得更快 - 考虑到所有现代 CPU 的东西,如管道和寄存器重命名。它来自同一个技巧,它包含使用 XOR EAX,EAX(我在科罗拉多州某人的车牌上看到的!)清除寄存器的想法,而不是明显但可能较慢的 MOV EAX, #0(我使用旧的符号) )。
在asm中,像perl一样,TMTOWTDI。
如果eax为零,则执行条件跳转,否则将在319e9处继续执行
在某些程序中,它们可用于检查缓冲区溢出。在分配空间的最顶部放置一个 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
我们可以看到 杰格,杰勒如果 testl %edx,%edx. jle .L3
我们可以很容易找到 杰勒是西装 (SF^OF)|ZF
,如果%EDX为零,则ZF = 1,但是如果%EDX不是零,则为-1,在测试之后,of = 0,sf = 1,因此flag = true,该实现跳转.sorry,我的英文程度不高