objdump
を使用してダンプした次のアセンブリコードでは、次のようになっています。
lea 0x0(%esi,%eiz,1),%esi
レジスターとは%eiz
?上記のコードはどういう意味ですか?
GCC LEA EIZを使用する理由 :を参照してください。
どうやら
%eiz
は、常にゼロと評価される疑似レジスタです(MIPSのr0
のように)。
.。
私は最終的に、binutilsの第一人者であるIan LanceTaylorによるメーリングリストの投稿を見つけました。 GCCがコードストリームにNOP命令を挿入して、適切な配置などを保証する場合があります。 NOP命令は1バイトかかるので、必要なだけ追加できると思います。しかし、Ian Lance Taylorによると、チップが1つの長い命令を実行する方が、多くの短い命令よりも高速です。したがって、7つのNOP命令を挿入するのではなく、代わりに1つの奇妙なLEAを使用します。これは、7バイトを使用し、意味的にはNOPと同等です。
(ゲームに非常に遅れていますが、これは興味深い追加のように見えました):これはレジスターではなく、Intel命令エンコーディングの癖です。 ModRMバイトを使用してメモリからロードする場合、8つの可能なレジスタを格納するためにレジスタフィールドに3ビットが使用されます。ただし、ESP(スタックポインタ)が「なる」場所は、プロセッサによって「SIBバイトがこの命令の後に続く」と解釈されます(つまり、拡張アドレッシングモードであり、 ESP)。作成者だけが知っている理由により、GNUアセンブラは、常にこの「レジスタが存在するゼロ」を「%eiz」レジスタとして表していました。Intel構文はそれを削除するだけです。 。
Andy Rossは、根底にある推論の多くを提供していますが、残念ながら間違っているか、少なくとも技術的な詳細について混乱しています。 _(%esp)
_としてデコードされる代わりに、ModR/Mバイトだけでは_(%esp)
_だけの実効アドレスをエンコードできないことは事実です。これは、SIBバイトも含まれていることを通知するために使用されます。ただし、_%eiz
_疑似レジスタは、SIBバイトが使用されたことを表すためにSIBバイトで常に使用されるとは限りません。
SIBバイト(スケール/インデックス/ベース)には3つの部分があります:インデックス(スケールが適用される_%eax
_や_%ecx
_などのレジスタ)、スケール(2の累乗)インデックスレジスタに乗算される1から8まで)、およびベース(スケーリングされたインデックスに追加される別のレジスタ)。これは、add %al,(%ebx,%ecx,2)
(マシンコード:_00 04 4b
_ --opcode、modr/m、sib(SIBバイトが使用されていても%eizレジスタがないことに注意してください))(またはIntel構文では、「BYTE PTR [ecx * 2 + ebx]、alを追加」)。
ただし、_%esp
_をSIBバイトのインデックスレジスタとして使用することはできません。このオプションを許可する代わりに、Intelは、スケーリングやインデックス付けなしでベースレジスタをそのまま使用するオプションを追加します。したがって、add %al,(%ecx)
(マシンコード:_00 01
_- opcode、modr/m)とadd %al,(%ecx)
(マシンコード:_00 04 21
_-)のケースを明確にするためopcode、modr/m、sib)、代わりに代替構文add %al,(%ecx,%eiz,1)
が使用されます(またはIntel構文の場合:_add BYTE PTR [ecx+eiz*1],al
_)。
そして、Sinanによってリンクされた記事で説明されているように、この特定の命令(lea 0x0(%esi,%eiz,1),%esi
)は単にマルチバイトnop(_esi = &*esi
_と同等)として使用されるため、nopのような命令は1つだけです。複数のnop命令の代わりに実行されます。