eax'a karşı "test" eax?


118

Bazı meclisleri anlamaya çalışıyorum.

Montaj aşağıdaki gibi, testlsatırla ilgileniyorum :

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

Ben o noktayı anlamaya çalışıyorum testlarasında %eaxve %eax? Bu kodun ayrıntılarının önemli olmadığını düşünüyorum, sadece testi kendi başına anlamaya çalışıyorum - değer her zaman doğru olmaz mıydı?

Yanıtlar:


91

eax0 mı , üstü veya altı mı olduğunu test eder . Bu durumda, eax0 ise atlama yapılır .


2
Bu popüler yanıtı daha iyi bir kanonik yanıta dönüştürmek için bir düzenleme yaptım "Bu TEST olayı neyle ilgili ve CMP'den nasıl farklı?" Gibi ima ediliyor. JE ve JZ'nin eşanlamlı anlamı hakkındaki yorumlar için kendi cevabımı aşağıya bakın. Lütfen düzenlememi gözden geçirin çünkü oldukça önemli ve hala sizin cevabınız.
Peter Cordes

@PeterCordes Niyetiniz için minnettarım, ancak düzenlemenizi geri alacağım. 1. Sizin "sesiniz" benimkinden çok farklı ve şu anda cevabımdan çok daha fazla okuyor. 2. Daha sorunlu olan, bayrakların testve arasında tam olarak aynı şekilde çıktığı iddiasıdır cmp. Evet, Cody'ye yaptığınız yorumlara dayanarak inancınızın bu olduğunu anlıyorum. Ancak benim yazıma koymak farklı bir konu; Bu , her durumda aynı olup olmadığını bilmediğim için, beklemeye istekli olduğum bir iddia değil .
Chris Jester-Young

1
@PeterCordes Biraz boş zaman bulursam, bu cevabı daha kanonik olacak şekilde açıklamak isterim. Yine de yazdığım gibi yazardım ve bir şeyleri nasıl yazdığım konusunda oldukça titizim. :-) Örneğin, ben yazmak istiyorum je, jz, cmpve test, ve JE, JZ, CMP veya TEST. Ben böyle seçiciyim.
Chris Jester-Young

1
Kendi cevabımı artırmaya çalışmıyordum. Aslında o düzenlemeyi yaptığımda bu soruyu kendim yanıtladığımı unuttum ve ancak daha sonra fark ettim. Birisi onu çarptıktan sonra buna baktım ve küçük bir kurgu çok fazla kartopu yaparak başlayan şey. Onu geri almak istemene gücen yok; bu sadece bir öneriydi ve kesinlikle benim işim gibi okunuyor, senin değil. Yazdıklarımın bir kısmını alıp kendi cevabıma koyacağım.
Peter Cordes

2
Vay canına, bu soruya verdiğim yanıtı sizinkine eklediklerimi içerecek şekilde düzenledikten sonra, Haziran ayında yazdıklarımın çoğunu neredeyse tamamen kopyaladığımı fark ettim. Hata! Bu iddiamı desteklemek test a,ave cmp $0,abayrakları aynı şekilde ayarlamak için daha fazla gerekçeyle güncelledim ; Bunun önemsiz bir iddiaya işaret ettiğin için teşekkürler. re: TEST vs test.: son zamanlarda Intel'in kılavuzları gibi tümü büyük harf kullanmaya başladım. Ancak AT&T anımsatıcılarına karşı Intel anımsatıcılarından bahsederken, testbAT&T için stil kullanıyorum . IDK, okunabilirliğe yardımcı oluyorsa.
Peter Cordes

90

Bunun anlamı testargümanları birlikte AND ve sonucu sıfır için kontrol etmektir. Bu kod, EAX'in sıfır olup olmadığını test eder. jesıfır ise atlayacak.

BTW, bu cmp eax, 0, derleyicilerin genellikle bu şekilde yapmasının nedeni olduğundan daha küçük bir talimat oluşturur .


34

Test talimatı, işlenenler arasında mantıksal bir AND işlemi yapar, ancak sonucu bir kayda geri yazmaz. Yalnızca bayraklar güncellenir.

Örneğinizde, test eax, eax, eax sıfırsa sıfır bayrağını, en yüksek bit ayarlanmışsa işaret bayrağını ve diğer bazı bayrakları da ayarlayacaktır.

Eşit (je) komutu sıfır bayrağı ayarlanmışsa atlarsa Atla.

Kodu aşağıdaki gibi daha okunabilir bir koda çevirebilirsiniz:

cmp eax, 0
je  somewhere

Bu aynı işlevselliğe sahiptir, ancak bazı baytlar daha fazla kod alanı gerektirir. Derleyicinin karşılaştırma yerine bir test yayınlamasının nedeni budur.


3
Aslında, cmp orada çalışmayabilir. Diğer bir deyişle, sunulan özel durum için çalışır, ancak cmp bayrakları testten farklı şekilde etkiler, çünkü ve yerine dahili bir alttır. Akılda tutulması gereken bir şey.
Cody Brocious

4
sıfıra karşı bir test için tamamen geçerlidir.
Nils Pipenbrinck

3
Ama daha sonra bayraklara başka ne bakacağını bilmiyorsun. Bayraklar üzerindeki etkiler çok farklıdır, bu nedenle bu bir sorun olabilir ve çoğu zaman öyledir.
Cody Brocious

2
Hayır, farklı bir / method / tarafından ayarlanan tek işaretler, her ikisi de 0'a ayarlanan taşıma ve taşmadır.
Cody Brocious

2
@CodyBrocious: test eax, eaxve cmp eax, 0her ikisi de tüm bayrakları ayarlar ve bunları aynı değerlere ayarlar. Her iki komut da tüm işaretleri "sonuca göre" ayarlar. Çıkarma 0asla taşıma veya taşma üretemez. Argümanınız 0 dışındaki herhangi bir an için doğru, ancak 0 için değil
Peter Cordes

22

testgibi andsadece değiştirilmemiş hem girdileri bırakarak BAYRAK yazar hariç. İki farklı girişle, bazı bitlerin tümünün sıfır olup olmadığını veya en az birinin ayarlanmış olup olmadığını test etmek için kullanışlıdır. (örneğin test al, 3, EAX 4'ün katı ise (ve bu nedenle her iki düşük 2 biti de sıfırlanmışsa) ZF'yi ayarlar.


test eax,eaxTüm bayrakları tamamen aynı şekilde ayarlar cmp eax, 0olur :

  • CF ve OF temizlendi (VE / TEST bunu her zaman yapar; sıfır çıkarmak asla bir taşıma oluşturmaz)
  • EAX'teki değere göre ZF, SF ve PF. ( a = a&a = a-0).
    (Her zamanki gibi PF yalnızca düşük 8 bit'e göre ayarlanır )

Eski AF (ASCII / BCD talimatları tarafından kullanılan yardımcı taşıma bayrağı) hariç. TEST onu tanımsız bırakır , ancak CMP onu "sonuca göre" ayarlar . Sıfırın çıkarılması 4. bitten 5. bite bir taşıma üretemeyeceğinden, CMP her zaman AF'yi temizlemelidir.


TEST daha küçüktür (ani değildir) ve bazen daha hızlıdır (CMP'den daha fazla durumda daha fazla CPU üzerinde bir karşılaştırma ve dallanma ile makro kaynaşabilir). Bu, testbir kaydı sıfıra karşı karşılaştırmak için tercih edilen deyimi yapar . cmp reg,0Anlamsal anlamı ne olursa olsun kullanabileceğiniz bir gözetleme deliği optimizasyonudur .

CMP'yi anında 0 ile kullanmanın tek yaygın nedeni, bir bellek işleneni ile karşılaştırmak istediğiniz zamandır. Örneğin, cmpb $0, (%esi)örtük uzunlukta bir C tarzı dizenin sonunda sonlandırıcı bir sıfır baytı kontrol etmek için.


AVX512F eklerkortestw k1, k2 ve AVX512DQ / BW (Skylake-X ama KNL değil) ekler ktestb/w/d/q k1, k2, bu AVX512 maske kayıtları (k0..k7) üzerinde çalışır, ancak yine testde tam sayı ORveya ANDtalimatlarda olduğu gibi normal FLAGS ayarlar . (SSE4 ptestveya SSE gibi sıralama ucomiss: SIMD etki alanındaki girişler ve tamsayı BAYRAKLAR ile sonuçlanır.)

kortestw k1,k1SSE / AVX2 (v)pmovmskb/ps/pd+ testveya yerine geçerek, AVX512 karşılaştırma sonucuna göre dallanma / cmovcc / setcc'nin deyimsel yoludur cmp.


Kullanımı jzvs. jekafa karıştırıcı olabilir.

jzve jekelimenin tam anlamıyla aynı talimattır , yani makine kodunda aynı işlem kodu. Aynı şeyi yaparlar, ancak insanlar için farklı anlamsal anlamları vardır . Dağıtıcılar (ve genellikle derleyicilerden gelen asm çıktısı) yalnızca bir tane kullanır, bu nedenle anlamsal ayrım kaybolur.

cmpve subiki girişi eşit olduğunda ZF'yi ayarlayın (yani çıkarma sonucu 0'dır). je(eşitse zıpla) anlamsal olarak ilişkili eşanlamlı.

test %eax,%eax/ and %eax,%eaxsonuç sıfır olduğunda ZF'yi tekrar ayarlar, ancak "eşitlik" testi yoktur. Testten sonra ZF size iki işlenenin eşit olup olmadığını söylemez. Yani jz(sıfırsa zıpla) anlamsal olarak alakalı eşanlamlı.


testBitsel andişlem olmakla ilgili temel bilgileri eklemeyi düşünürdüm , sadece montajı öğrenen insanlar için açık olmayabilir (ve her 60 saniyede bir talimat başvuru kılavuzunu kontrol etmenin tembel / habersiz olması;) :)).
Ped7g

1
@ Ped7g: Yeterince adil, sanırım bu bölümü diğer cevaplara bırakmak yerine her şeyi bu cevaba koymak zarar vermez. AVX512 eklendi kortest*ve ktest*ben oradayken .
Peter Cordes

BTW, bu temelde aynı sorunun başka bir versiyonuna verdiğim yanıtla aynı , ancak oradaki performansla ilgili daha fazla şey söyledim, örneğin muhtemelen Nehalem gibi eski P6 ailesi CPU'larda kaydı aynı değerle yeniden yazarak yazma-okuma duraklamalarını önlemek.
Peter Cordes

@PeterCordes Kabul edilen cevap bu olmalıdır: kapsamlı ve teknik. Kabul edilen gönderinin aksine, bu kişinin merakını ve bilgiye olan susuzluğunu giderir. Devam edin efendim.
programmersn

PF'nin, bu durumda AL olan düşük 8 bitlik pariteye ayarlandığına dikkat edilmelidir.
ecm

5

Bu kod parçası, bir şeye, muhtemelen bir yapıya veya nesneye işaretçi verilen bir alt yordamdan. 2. satır, o şeyden bir değer getirerek bu işaretçiyi referans alır - muhtemelen kendisi bir işaretçi veya belki de sadece bir int, 2. üyesi olarak saklanır (ofset +4). 3. ve 4. satırlar bu değeri sıfır için test eder (bir işaretçi ise NULL) ve sıfır ise aşağıdaki birkaç işlemi (gösterilmemiştir) atlar.

Sıfır testi bazen anlık gerçek sıfır değeriyle karşılaştırılarak kodlanır, ancak bunu yazan derleyici (veya insan?), Ardışık düzen ve kayıt gibi tüm modern CPU öğelerini dikkate alarak bir test operasyonunun daha hızlı çalışacağını düşünebilirdi. yeniden adlandırma. Açık ama belki de daha yavaş olan MOV EAX, # 0 (daha eski bir notasyon kullanıyorum) yerine XOR EAX, EAX (Colorado'da birinin plakasında gördüğüm!) ).

Asm'de, perl gibi, TMTOWTDI.


3

Eax sıfırsa koşullu atlamayı gerçekleştirecek, aksi takdirde yürütmeye 319e9'da devam edecektir.


0

Bazı programlarda bir arabellek taşmasını kontrol etmek için kullanılabilirler. Ayrılan alanın en üstüne bir 0 yerleştirilir. Yığına veri girdikten sonra, tahsis edilen alanın taşmadığından emin olmak için tahsis edilen alanın en başında 0'ı arar.

Bu, istismar egzersizlerinin stack0 alıştırmasında, taşıp taşmadığını kontrol etmek için kullanıldı ve eğer yoksa ve orada sıfır varsa, "Tekrar dene" ifadesini gösterecekti.

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

Sıfır olmayan bir kayıt için kontrol etmenin bu özel durumunun bu Soru-Cevap'a ne kattığını anlamıyorum. Özellikle cmp DWORD PTR [esp+0x5c], 0/ jz 0x8048427 <main+51>ayrı bir MOV yüklemesinden daha verimli olduğunda ve sonra TEST. Bu, sıfırı kontrol etmek için yaygın bir kullanım durumu değildir.
Peter Cordes

-4

biz görebiliyordu JG , JLE Eğer testl %edx,%edx. jle .L3bunu kolay bulabiliriz jle giysidir (SF^OF)|ZF% edx sıfır değildir ve -1, testl sonra eğer% edx, ZF = 1 sıfırsa, ancak, OF = 0 ve SF = 1, bu yüzden atlama uygulayan bayrak = true, üzgünüm, İngilizcem zayıf

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.