`testl` eax 与 eax 对比?

发布于 2024-07-05 23:37:09 字数 395 浏览 15 评论 0原文

我试图理解一些组装。

程序集如下,我对 testl 行感兴趣:

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

我试图理解 %eax之间的 testl 点%eax ? 我认为这段代码的细节并不重要,我只是想理解测试本身 - 该值不总是正确的吗?

I am trying to understand some assembly.

The assembly as follows, I am interested in the testl line:

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

I am trying to understand that point of testl between %eax and %eax? I think the specifics of what this code isn't important, I am just trying to understand the test with itself - wouldn't the value always be true?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

半暖夏伤 2024-07-12 23:37:13

我们可以看到jgjle
如果 testl %edx,%edx。 jle .L3我们很容易发现jle适合(SF^OF)|ZF,如果%edx为零,ZF=1,但如果%edx不为零,为-1,testl后,OF=0,SF=1,所以flag=true,实现跳转
.抱歉,我的英语很差

we could see the jgjle
If testl %edx,%edx. jle .L3we could easy find jleis suit (SF^OF)|ZF,if %edx is zero ,ZF=1,but if %edx is not zero and is -1,after the testl ,the OF=0,and the SF =1,so the flag =true,that implement jump
.sorry ,my English is poor

聊慰 2024-07-12 23:37:12

test 就像and,但它只写入 FLAGS,而其两个输入均未修改。 对于两个不同输入,它对于测试某些位是否全为零或是否至少设置了一个非常有用。 (例如,如果 EAX 是 4 的倍数,则 test al, 3 设置 ZF(因此其低 2 位均为零)。


test eax,eax 设置所有标志的方式与 cmp eax, 0

  • CF 和 OF 被清除(AND/TEST 总是这样做;减去零 从不产生进位)
  • 根据 EAX 中的值 ZF、SF 和 PF (a = a&a = a-0)。
    (PF照常只是根据低8位设置)

已过时的 AF(辅助进位标志,由 ASCII/BCD 指令使用)除外。 TEST 未定义,但是CMP“根据结果”设置它。 由于减零不能产生第 4 到第 5 位的进位,因此 CMP 应始终清除 AF。


TEST 更小(不是立即执行),有时更快(与 CMP 相比,在更多情况下可以在更多 CPU 上宏融合到比较和分支微指令中)。 这使得 test< /code> 将寄存器与零进行比较的首选习惯用法。 这是 cmp reg,0 的窥孔优化,无论语义如何,您都可以使用它。

使用带有立即数 0 的 CMP 的唯一常见原因是当您想要与内存操作数进行比较时。 例如,cmpb $0, (%esi) 用于检查隐式长度 C 样式字符串末尾是否有终止零字节。


AVX512F 添加 kortestw k1, k2< /strong> 和 AVX512DQ/BW(Skylake-X 但不是 KNL)添加 ktestb/ w/d/q k1, k2,它们在 AVX512 掩码寄存器 (k0..k7) 上运行,但仍然像 test 一样设置常规标志,与整数相同ORAND 指令即可。 (有点像 SSE4 ptest 或 SSE ucommiss:SIMD 域中的输入并产生整数 FLAGS。)

kortestw k1,k1 是惯用的基于 AVX512 比较结果分支 / cmovcc / setcc 的方式,替换 SSE/AVX2 (v)pmovmskb/ps/pd + testcmp


使用 jzje 可能会造成混淆。

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

cmpsub 当它们的两个输入相等(即减法结果为0)时设置ZF。 je(如果相等则跳转)是语义相关的同义词。

test %eax,%eax / 和 %eax,%eax 当结果为零时再次设置 ZF,但没有“相等”测试。 测试后的 ZF 不会告诉您两个操作数是否相等。 所以jz(如果为零则跳转)是语义相关的同义词。

test is like and, except it only writes FLAGS, leaving both its inputs unmodified. With two different inputs, it's useful for testing if some bits are all zero, or if at least one is set. (e.g. test al, 3 sets ZF if EAX is a multiple of 4 (and thus has both of its low 2 bits zeroed).


test eax,eax sets all flags exactly the same way that cmp eax, 0 would:

  • CF and OF cleared (AND/TEST always does that; subtracting zero never produces a carry)
  • ZF, SF and PF according to the value in EAX. (a = a&a = a-0).
    (PF as usual is only set according to the low 8 bits)

Except for the obsolete AF (auxiliary-carry flag, used by ASCII/BCD instructions). TEST leaves it undefined, but CMP sets it "according to the result". Since subtracting zero can't produce a carry from the 4th to 5th bit, CMP should always clear AF.


TEST is smaller (no immediate) and sometimes faster (can macro-fuse into a compare-and-branch uop on more CPUs in more cases than CMP). That makes test the preferred idiom for comparing a register against zero. It's a peephole optimization for cmp reg,0 that you can use regardless of the semantic meaning.

The only common reason for using CMP with an immediate 0 is when you want to compare against a memory operand. For example, cmpb $0, (%esi) to check for a terminating zero byte at the end of an implicit-length C-style string.


AVX512F adds kortestw k1, k2 and AVX512DQ/BW (Skylake-X but not KNL) add ktestb/w/d/q k1, k2, which operate on AVX512 mask registers (k0..k7) but still set regular FLAGS like test does, the same way that integer OR or AND instructions do. (Sort of like SSE4 ptest or SSE ucomiss: inputs in the SIMD domain and result in integer FLAGS.)

kortestw k1,k1 is the idiomatic way to branch / cmovcc / setcc based on an AVX512 compare result, replacing SSE/AVX2 (v)pmovmskb/ps/pd + test or cmp.


Use of jz vs. je can be confusing.

jz and je are literally the same instruction, i.e. the same opcode in the machine code. They do the same thing, but have different semantic meaning for humans. Disassemblers (and typically asm output from compilers) will only ever use one, so the semantic distinction is lost.

cmp and sub set ZF when their two inputs are equal (i.e. the subtraction result is 0). je (jump if equal) is the semantically relevant synonym.

test %eax,%eax / and %eax,%eax again sets ZF when the result is zero, but there's no "equality" test. ZF after test doesn't tell you whether the two operands were equal. So jz (jump if zero) is the semantically relevant synonym.

一江春梦 2024-07-12 23:37:12

这段代码来自一个子例程,该子例程被赋予了一个指向某个东西的指针,可能是某个结构或对象。 第二行取消引用该指针,从该指针获取一个值 - 可能本身是一个指针,也可能只是一个 int,存储为其第二个成员(偏移量 +4)。 第 3 行和第 4 行测试该值是否为零(如果它是指针,则为 NULL),如果它为零,则跳过以下几个操作(未显示)。

对零的测试有时被编码为与立即文字零值的比较,但编写此代码的编译器(或人类?)可能认为 testl 操作会运行得更快 - 考虑到所有现代 CPU 的东西,如管道和寄存器重命名。 它来自同一个技巧,它包含使用 XOR EAX,EAX(我在科罗拉多州某人的车牌上看到的!)清除寄存器的想法,而不是明显但可能较慢的 MOV EAX, #0(我使用旧的符号) )。

在asm中,像perl一样,TMTOWTDI。

This snippet of code is from a subroutine that was given a pointer to something, probably some struct or object. The 2nd line dereferences that pointer, fetching a value from that thing - possibly itself a pointer or maybe just an int, stored as its 2nd member (offset +4). The 3rd and 4th lines test this value for zero (NULL if it's a pointer) and skip the following few operations (not shown) if it is zero.

The test for zero sometimes is coded as a compare to an immediate literal zero value, but the compiler (or human?) who wrote this might have thought a testl op would run faster - taking into consideration all the modern CPU stuff like pipelining and register renaming. It's from the same bag of tricks that holds the idea of clearing a register with XOR EAX,EAX (which i saw on someone's license plate in Colorado!) rather than the obvious but maybe slower MOV EAX, #0 (i use an older notation).

In asm, like perl, TMTOWTDI.

稍尽春風 2024-07-12 23:37:12

在某些程序中,它们可用于检查缓冲区溢出。
在分配空间的最顶部放置一个 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

In some programs they can be used to check for a buffer overflow.
At the very top of the allocated space a 0 is placed. After inputting data into the stack, it looks for the 0 at the very beginning of the allocated space to make sure the allocated space is not overflowed.

It was used in the stack0 exercise of exploits-exercises to check if it was overflowed and if there wasnt and there was a zero there, it would display "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
纵性 2024-07-12 23:37:12

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

If eax is zero it will perform the conditional jump, otherwise it will continue execution at 319e9

梦里兽 2024-07-12 23:37:11

测试指令在操作数之间执行逻辑与运算,但不会将结果写回到寄存器中。 仅更新标志。

在您的示例中,测试 eax,如果 eax 为零,则 eax 将设置零标志,如果设置了最高位,则 eax 将设置符号标志以及其他一些标志。

如果设置了零标志,则跳转(je)指令将跳转。

您可以将代码转换为更具可读性的代码,如下所示:

cmp eax, 0
je  somewhere

具有相同的功能,但需要更多字节的代码空间。 这就是编译器发出测试而不是比较的原因。

The test instruction does a logical AND-operation between the operands but does not write the result back into a register. Only the flags are updated.

In your example the test eax, eax will set the zero flag if eax is zero, the sign-flag if the highest bit set and some other flags as well.

The Jump if Equal (je) instruction jumps if the zero flag is set.

You can translate the code to a more readable code like this:

cmp eax, 0
je  somewhere

That has the same functionality but requires some bytes more code-space. That's the reason why the compiler emitted a test instead of a compare.

皓月长歌 2024-07-12 23:37:11

它测试 eax 是否为 0、或大于或小于 0。 在这种情况下,如果eax为0,则进行跳转。

It tests whether eax is 0, or above, or below. In this case, the jump is taken if eax is 0.

旧话新听 2024-07-12 23:37:10

test 的含义是将参数与在一起,并检查结果是否为零。 所以这段代码测试 EAX 是否为零。 如果为零,je 将跳转。

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

The meaning of test is to AND the arguments together, and check the result for zero. So this code tests if EAX is zero or not. je will jump if zero.

BTW, this generates a smaller instruction than cmp eax, 0 which is the reason that compilers will generally do it this way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文