回答:
eax
が0以上か、それとも以下かをテストします。この場合、ジャンプeax
は0の場合に行われます。
test
との間でまったく同じように出力されるという大胆な主張ですcmp
。はい、私はあなたのコーディへのコメントに基づくあなたの信念だと理解しています。しかし、それを私の投稿に入れるのは別の問題です。それがすべてのケースで同一かどうかわからないという理由だけで、私が待機する意思のある主張ではありません。
je
、jz
、cmp
、とtest
、とないJE、JZ、CMP、またはTEST。私はそのようなうるさいです。
test a,a
し、cmp $0,a
同じようにフラグを設定します。それは重要な主張だと指摘してくれてありがとう。re:TEST vs.:test
最近、Intelのマニュアルのようにすべて大文字を使い始めました。しかし、AT&TのニーモニックとIntelのニーモニックについて話すときはtestb
、AT&Tのスタイルを使用します。IDKが読みやすくなる場合。
テスト命令は、オペランド間で論理AND演算を行いますが、結果をレジスタに書き戻しません。フラグのみが更新されます。
あなたの例では、テストeax、eaxは、eaxがゼロの場合はゼロフラグを設定し、最上位ビットが設定されている場合は符号フラグを設定し、他のいくつかのフラグも設定します。
ゼロフラグが設定されている場合、Jump if Equal(je)命令がジャンプします。
このコードを次のような読みやすいコードに変換できます。
cmp eax, 0
je somewhere
これには同じ機能がありますが、数バイトのコードスペースが必要です。これが、コンパイラが比較ではなくテストを発行した理由です。
test eax, eax
とcmp eax, 0
の両方がすべてのフラグを設定して、同じ値に設定します。どちらの命令も、「結果に従って」すべてのフラグを設定します。減算0
によってキャリーやオーバーフローが発生することはありません。あなたの引数が0以外の任意の即時の正しいではなく0です
test
and
FLAGSのみを書き込み、両方の入力を変更せずに残すことを除いて、に似ています。2つの異なる入力を使用すると、一部のビットがすべてゼロであるか、少なくとも1つが設定されているかをテストするのに役立ちます。(たとえばtest al, 3
、EAXが4の倍数である場合にZFを設定します(したがって、下位2ビットの両方がゼロに設定されます)。
test eax,eax
すべてのフラグにまったく同じように設定cmp eax, 0
だろうが。
a = a&a = a-0
)。廃止されたAF(ASCII / BCD命令で使用される補助キャリーフラグ)を除きます。 TESTはそれを未定義のままにしますが、CMPは「結果に従って」それを設定します。ゼロを減算すると、4番目から5番目のビットからキャリーが生成されないため、CMPは常にAFをクリアする必要があります。
TESTはより小さく(即時ではなく)、場合によってはより高速です(CMPよりも多くの場合、より多くのCPUで比較および分岐uopにマクロ融合できます)。 これによりtest
、レジスターをゼロと比較するための推奨イディオムになります。これcmp reg,0
は、意味の意味に関係なく使用できるのぞき穴の最適化です。
CMPを即値0で使用する唯一の一般的な理由は、メモリオペランドと比較する場合です。たとえばcmpb $0, (%esi)
、暗黙の長さのCスタイルの文字列の末尾にある終了ゼロバイトをチェックするには、
AVX512F addkortestw k1, k2
とAVX512DQ / BW(Skylake-XではなくKNL)add は、整数または命令と同じ方法で、ktestb/w/d/q k1, k2
AVX512マスクレジスタ(k0..k7)で動作しますtest
が、通常のFLAGSのように設定します。(SSE4 またはSSE のようなソート:SIMDドメイン内の入力と整数FLAGSになります。)OR
AND
ptest
ucomiss
kortestw k1,k1
AVX512の比較結果に基づいて/ cmovcc / setccを分岐し、SSE / AVX2 (v)pmovmskb/ps/pd
+ test
またはを置き換える慣用的な方法cmp
です。
jz
vsの使用はje
混乱を招く可能性があります。
jz
そしてje
、文字通り同じ命令です。つまり、マシンコードの同じオペコードです。 それらは同じことを行いますが、人間にとっては意味的な意味が異なります。逆アセンブラー(および通常はコンパイラーからのasm出力)は1つしか使用しないため、意味上の違いは失われます。
cmp
sub
2つの入力が等しい場合(つまり、減算結果が0の場合)にZF を設定します。 je
(等しい場合はジャンプ)は、意味的に関連する同義語です。
test %eax,%eax
/ and %eax,%eax
は、結果がゼロのときにZFを設定しますが、「等価」テストはありません。テスト後のZFでは、2つのオペランドが等しいかどうかはわかりません。したがって、jz
(ゼロの場合はジャンプ)は、意味的に関連する同義語です。
test
ビット単位のand
操作であることに関する基本情報を追加することを検討します。アセンブリを学習しているだけの人には明らかではないかもしれません(そして60秒ごとに命令リファレンスガイドをチェックするのが面倒/気づいていません;):))。
kortest*
を追加しましktest*
た。
このコードスニペットは、何かへのポインタ(おそらく何らかの構造体またはオブジェクト)が与えられたサブルーチンからのものです。2行目はそのポインターを逆参照し、そのポインターから値をフェッチします-おそらくそれ自体がポインター、または単にintで、2番目のメンバー(オフセット+4)として保存されます。3行目と4行目は、この値がゼロかどうか(ポインターの場合はNULL)をテストし、ゼロの場合は以下のいくつかの操作(図示せず)をスキップします。
ゼロのテストは、即時のリテラルゼロ値との比較としてコーディングされる場合がありますが、これを書いたコンパイラー(または人間?)は、パイプラインやレジスターなどのすべての最新のCPUを考慮して、testl opがより高速に実行されると考えているかもしれません名前の変更。それは、明白な、しかしおそらく遅いMOV EAX、#0(私は古い表記を使用しています)ではなく、XOR EAX、EAX(コロラドの誰かのナンバープレートで見ました!) )。
asmでは、perlと同様、TMTOWTDI。
一部のプログラムでは、バッファオーバーフローのチェックに使用できます。割り当てられたスペースの最上部に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
cmp DWORD PTR [esp+0x5c], 0
/ jz 0x8048427 <main+51>
が別のMOVロードとテストよりも効率的だった場合。これは、ゼロをチェックするための一般的なユースケースではありません。