「testl」はeaxに対してeaxですか?
-
02-07-2019 - |
質問
アセンブリを理解しようとしています。
アセンブリは次のとおりです。 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
を追加しますa> および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、私の英語は下手です