webdevqa.jp.net

「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のポイントを理解しようとしていますか?このコードが重要ではないことの詳細は、自分自身でテストを理解しようとしているだけだと思います-値は常に真実ではないでしょうか?

112
maxpenguin

eaxが0以上、または以下かどうかをテストします。この場合、eaxが0の場合にジャンプします。

85

testの意味は、引数をANDで結合し、ゼロの結果をチェックすることです。したがって、このコードはEAXがゼロかどうかをテストします。 jeはゼロの場合ジャンプします。

ところで、これはcmp eax, 0よりも小さな命令を生成します。これがコンパイラーが通常この方法で行う理由です。

88
Mike F

テスト命令は、オペランド間で論理AND演算を実行しますが、結果をレジスタに書き戻しません。フラグのみが更新されます。

テストeaxの例では、eaxは、eaxがゼロの場合はゼロフラグを設定し、最上位ビットが設定されている場合は符号フラグを設定し、その他のフラグも設定します。

ゼロフラグが設定されている場合、Jump if Equal(je)命令はジャンプします。

コードを次のような読みやすいコードに変換できます。

cmp eax, 0
je  somewhere

これには同じ機能がありますが、コードバイトがさらに数バイト必要です。これが、コンパイラが比較の代わりにテストを発行した理由です。

33

testand と似ていますが、FLAGSのみを書き込み、両方の入力を変更しないままにします。 2つのdifferent入力では、一部のビットがすべてゼロかどうか、または少なくとも1つのビットが設定されているかどうかをテストするのに役立ちます。 (たとえば、test al, 3_は、EAXが4の倍数である(したがって、下位2ビットの両方がゼロになっている)場合にZFを設定します。


_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でマクロヒューズを比較分岐uopにできます)。 これは、testを、レジスタをゼロと比較するための好ましいイディオムにする 。これは、セマンティックな意味に関係なく使用できる_cmp reg,0_のピープホール最適化です。

即時0でCMPを使用する唯一の一般的な理由は、メモリオペランドと比較する場合です。たとえば、cmpb $0, (%esi)は、暗黙的な長さのCスタイル文字列の末尾にあるゼロの終端をチェックします。


AVX512Fは _kortestw k1, k2_を追加し、AVX512DQ/BW(Skylake-XがKNLではない)を追加 _ktestb/w/d/q k1, k2_ 、AVX512マスクレジスタ(k0..k7)で動作しますが、testのように通常のフラグを設定します。整数ORまたはAND指示があります。 (SSE4のようなptestまたはSSE ucomiss:SIMDドメインの入力で、整数FLAGSになります。)

_kortestw k1,k1_は、AVX512比較結果に基づいて、SSE/AVX2の_(v)pmovmskb/ps/pd_ + testまたはcmpを置換する慣用的な方法です。


jzjeの使用は混乱を招く可能性があります。

jzjeは、文字通り同じ命令 、つまりマシンコードの同じオペコードです。これらは同じことをしますが、人間に対して異なる意味を持ちます。逆アセンブラー(および通常、コンパイラーからのasm出力)は1つだけを使用するため、セマンティックの区別は失われます。

cmpsubは、2つの入力が等しい(つまり、減算結果が0)場合にZFを設定します。 je(等しい場合はジャンプ)は、意味的に関連する同義語です。

_test %eax,%eax_/_and %eax,%eax_は、結果がゼロのときに再びZFを設定しますが、「等価」テストはありません。テスト後のZFでは、2つのオペランドが等しいかどうかはわかりません。したがって、jz(ゼロの場合はジャンプ)は意味的に関連する同義語です。

20
Peter Cordes

このコードスニペットは、何か、おそらくいくつかの構造体またはオブジェクトへのポインターが与えられたサブルーチンからのものです。 2行目はそのポインターを逆参照し、そのことから値を取得します-おそらくそれ自体がポインターであるか、2番目のメンバー(オフセット+4)として格納されているintだけです。 3行目と4行目では、この値をゼロ(ポインターの場合はNULL)でテストし、ゼロの場合は次のいくつかの操作(図示せず)をスキップします。

ゼロのテストは、即時リテラルのゼロ値との比較としてコーディングされる場合がありますが、これを書いたコンパイラー(または人間?)は、パイプラインやレジスターなどの最新のCPUをすべて考慮して、testl opの実行が高速になると考えたかもしれません名前を変更します。明らかですが、より遅いMOV EAXではなく、XOR EAX、EAX(コロラドの誰かのナンバープレートで見た!)でレジスタをクリアするという考えを保持しているのと同じトリックの袋からです。 、#0(古い表記を使用)。

Asmでは、Perlと同様に、TMTOWTDI。

5
DarenW

Eaxがゼロの場合は条件付きジャンプを実行し、そうでない場合は319e9で実行を継続します

3
Mike Thompson

一部のプログラムでは、バッファオーバーフローをチェックするために使用できます。割り当てられたスペースの最上部に0が配置されます。スタックにデータを入力した後、割り当てられたスペースの先頭で0を探し、割り当てられたスペースがオーバーフローしないようにします。

これは、エクスプロイトエクササイズのstack0エクササイズで使用され、オーバーフローしたかどうかをチェックし、ゼロがなかった場合は「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 <[email protected]>
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 <[email protected]>
0x08048425 <main+49>:   jmp    0x8048433 <main+63>
0x08048427 <main+51>:   mov    DWORD PTR [esp],0x8048529
0x0804842e <main+58>:   call   0x804832c <[email protected]>
0x08048433 <main+63>:   leave
0x08048434 <main+64>:   ret
0
user7259278