質問

アセンブリを理解しようとしています。

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

役に立ちましたか?

解決

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

他のヒント

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

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

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

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

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

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

cmp eax, 0
je  somewhere

同じ機能を備えていますが、コードスペースが数バイト必要です。これが、コンパイラが比較ではなくテストを発行した理由です。

test and 。ただし、FLAGSのみを書き込み、両方の入力は変更されません。 2つの異なる入力では、一部のビットがすべてゼロであるか、少なくとも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

(廃止されたAF(ASCII / BCD命令で使用される補助キャリーフラグを除く)。 TESTは未定義のままにしますが、 CMPは「結果に応じて」設定します。ゼロを減算しても、4番目から5番目のビットの桁上げは生成されないため、CMPは常にAFをクリアする必要があります。


TESTは小さく(即時ではありません)、時には高速です(CMPよりも多くの場合、より多くのCPUで比較分岐uopにマクロ融合できます)。 test レジスタをゼロであるかどうかをテストするための好ましいイディオム

即時0でCMPを使用する唯一の一般的な理由は、メモリオペランドと比較する場合です(たとえば、 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 は、SSE / AVX2 (v)pmovmskb / ps / pd を置き換えるAVX512比較結果に基づいて/ cmovcc / setccを分岐する慣用的な方法です。 + test または cmp


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

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

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

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

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

ゼロのテストは、即時リテラルのゼロ値との比較としてコーディングされる場合がありますが、これを書いたコンパイラー(または人間?)は、testl opの方が高速になると考えているかもしれません。パイプライン処理とレジスタの名前変更。 XOR EAX、EAX(コロラドの誰かのナンバープレートで見た!)でレジスタをクリアするというアイデアを保持しているのと同じトリックのバッグからです。 )。

perm、TMTOWTDIなどのasmで。

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

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

エクスプロイトエクササイズの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

jg &#65292; jle が表示されました testl%edx、%edxの場合。 jle .L3 jle がスーツ(SF ^ OF)| ZF であることを簡単に見つけることができます。%edxがゼロの場合、ZF = 1ですが、%edxの場合testl、OF = 0、SF = 1の後、ゼロではなく-1であるため、ジャンプを実装するフラグ= true .sorry、私の英語は下手です

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top