1

わかりましたので、開発中のOS用のアセンブラを書いています。私はすべてのmov命令を持っていますが、callやjmpなどの命令を実装したいと思っています。私は本当に良いドキュメントを持っていないので、NASM によって生成されたマシン コードを調べて、オペコードなどを見つけています。call のオペコードが何であるかを確認したかったので、最初からラベルで始まるコードをコンパイルしました。呼び出しオペコードの後のアドレスは 00 00 00 00 だと思っていましたが、FB FF FF FF でした。シンボルに関係があると思ったので、call 0x000000 でコードをコンパイルして何が起こったのかを確認したところ、アドレスはまったく同じ (0xFBFFFFFF) でした。誰かが私にこれを説明できますか?私は混乱しています。

4

3 に答える 3

4

逆アセンブルしている実際のコードを表示すると便利です。ほとんどの場合、その数値はリトルエンディアンの負のオフセットです。2 の補数で 0xFFFFFFFB = -5。書きましたか:

Label: call Label

call が 4 バイトの相対オフセットを持つ 1 バイトのオペコードである場合、それは理にかなっています。

于 2012-08-31T08:36:22.043 に答える
1

32 ビット ユーザー モード x86 コードでの CALL の最も一般的な形式はCALL rel32、オペランドのポイントと次の命令のアドレスを "呼び出す" です。これは近相対呼び出しです。

参考までに、絶対呼び出しを使用することは可能ですが、エンコーディングは 5 バイトではなく 6 バイトです。エンコーディングは になりますFF 14 XX XX XX XX。余分なバイト ( 14) は、即値として使用される即値変位を読み取るよう命令に指示します。ただし、これは、プログラムがロードされるモジュール ベースに応じて書き直す必要があります。相対呼び出しは、再配置時に注意する必要はありません。

これがどのように機能するかを視覚化するために、命令が実行されると、次のことが起こります。

  • EIP(命令ポインター) は、次の命令を指すようにインクリメントされます。
  • そのアドレスは (戻りアドレスを提供するために) スタックにプッシュされます。
  • 即値 (たとえば、rel32 値) が に追加されEIP
  • 次の命令は[EIP]通常どおり (新しい) から読み取られます。

この命令をエンコードすると、次のようになりますE8 XX XX XX XX。このことから、命令の長さが 5 バイトであることがわかります。

は命令の長さだけインクリメントされるためEIP、呼び出しは命令の開始から 5 バイト後のポイントに相対的になります。したがって、CALL 0x00000000 命令の相対アドレスが 0x00000000 である場合、 から 5 を引く必要がありEIPます。アセンブラが絶対アドレスを相対アドレスに変換しました。

オフセットは負になる場合があります。また、x86 アドレスはリトルエンディアンであることを思い出してください。したがって、命令はE8 FB FF FF FFです。

興味深いことに、この特定の命令の結果は、例外 ( ) が生成されるEIP+5まで継続的にスタックにプッシュされます。#SS(0)

于 2013-05-08T09:44:59.473 に答える
0

call多くの場合、さまざまな形式で提供されます。たとえば、絶対アドレスを使用してジャンプするものや、現在のアドレスに相対的にジャンプするものなどです。これは相対的なものである可能性がありますが、4 バイトはおそらく直接のオフセットではありません。

疑問がある場合、特にアセンブラを実装する場合は、マニュアルまたはデータシートを参照してください。

于 2012-08-31T08:35:18.053 に答える