我试图理解一些组装。

组装如下,我感兴趣的是 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.


用于 jzje 可能会令人困惑。

jzje 实际上是相同的指令, , IE。机器码中的操作码相同。 它们做同样的事情,但对人类来说具有不同的语义意义. 。反汇编器(通常是编译器的 asm 输出)只会使用一个,因此语义区别就会丢失。

cmpsub 当两个输入相等时设置 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,我的英文程度不高

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top