12

objdump -Dバイナリを逆アセンブルするために使用するように、 の典型的なコードjmpqは のようなものe9 7f fe ff ffで、負のオフセットを表すために使用されます。ただし、x86-64 のアドレスは (私の知る限り) 64(48) ビットなので、この 32 ビット アドレスはどのよう7f fe ff ffにして 64 ビット絶対アドレスの負のオフセットを表すのでしょうか?

jmpさらに、やのような他の命令はありますjmpqが、64 ビットのアドレス置換がありますか? Intel または AMD のマニュアルで手順を見つけるにはどうすればよいですか (検索してjmpqも何も見つかりませんでした)。


調べてみると、RIP相対アドレッシングと呼ばれているようです。そして、すべての命令がこれを行うわけではないようです。64 ビット相対アドレッシングはありますか? 間接ジャンプなら64ビットの絶対アドレスはレジスタかメモリにあるでしょ?

4

3 に答える 3

8

他の人が指摘したように、x86-64の「jmp relative」命令は、プログラムカウンターに対する相対オフセットとして使用される32ビットの符号付き変位に制限されています。

OPは、64ビットオフセットで相対ジャンプがない理由を尋ねました。Intel の設計者を代弁することはできませんが、特に 32 ビットの相対 jmp が利用できる場合、この命令があまり役に立たないことは明らかです。これが必要になるのは、プログラムのサイズが 2 GB 以上で、32 ビットの相対 jmp がプログラム内のどのポイントからもすべてに到達できない場合のみです。最近、2Gb のオブジェクト ファイルを見ましたか? したがって、そのような命令の明らかな有用性は非常に小さいようです。

ほとんどの場合、プログラムが非常に大きくなると、さまざまな速度で進化できる、より管理しやすい要素に分割され始めます。(DLL はこの例です)。そのような要素間のインターフェースは、より難解な手段 (ジャンプベクトルなど) によって行われ、進化に直面してもインターフェースが一定に保たれるようにします。非常に長い jmp 相対を使用して、アプリケーションから別のモジュールのエントリ ポイントに到達できますが、絶対アドレスをレジスタにロードしてレジスタ間接呼び出しを実行する実際のコストは、実際には十分小さいため、最適化する価値はありません。そして、最新の CPU 設計は、パフォーマンスを最大化するためにトランジスタを配置する場所を最適化することがすべてです。

完全を期すために、x86 (多くのフレーバー) にも非常に短い jmp 相対命令 (8 ビットの符号付きオフセット) があります。実際には、特にコード ブロックを再配置できる優れたコード ジェネレーターがある場合は、32 ビットの jmp 相対命令でさえほとんど必要ありません。インテルはおそらく、同じ理由でこれらを除外できたはずです。それらの有用性は、トランジスタを正当化するのに十分高いと思います。

「大きなリテラル オペランド」の問題は、多くのアーキテクチャで面白い形で現れます。コード内のリテラル値の分布を調べると、小さな値 (0、1、ASCII 文字コード) がかなりの割合を占めていることがわかります。他のほとんどすべてはメモリアドレスです。したがって、プログラムで「大きなリテラル値」は必要ありませんが、何らかの方法でメモリアドレスを処理する必要があります。Sparc チップには、「レジスタへの下位のリテラル値のロード」(「小さな定数」を意味する) と、あまり使用されない「上位のリテラル値のロード」(レジスタの上位ビットを埋める) があり、大きな定数を作成するための 2 番目の命令として使用されます。あまり使用されません。これにより、大きな定数が必要な場合を除いて、コードが小さく保たれます。

于 2014-11-16T13:08:21.783 に答える
7

64 ビット モードの E9 オペコードは、64 ビットに拡張された 32 ビットの符号置換符号を使用します。

E9 cd -> JMP rel32 -> 近くにジャンプ、相対、RIP = RIP + 64 ビットに拡張された 32 ビットの変位符号

FF オペコードを使用して、64 ビット アドレスにジャンプできます。

FF /4 -> JMP r/m64 -> 近くにジャンプ、絶対間接、RIP = レジスタまたはメモリからの 64 ビット オフセット

JMPのIntel 命令セット マニュアル エントリからの引用。

于 2014-11-16T08:55:14.287 に答える
2

以下は 64 ビットモードに適用されます。

JMP は、直接または間接的に実行できます。

直接ジャンプは、命令ポインターに関連していますRIP。ダイレクトジャンプには、ショートジャンプとニアジャンプの 2 種類があります。

  • ショート ジャンプは、OpcodeEBの後に 8 ビットの符号付き変位を使用するため、RIP –128 to +127バイトになります。
  • ニア ジャンプはオペコードE9を使用し、その後に 32 ビットの符号付き変位が続くため、RIP -2147483648 to +2147483647.

アセンブラは、2 バイトしか必要としないため、可能な場合はショート ジャンプを使用します。nearしかし、NASM では、次のキーワードを使用してニア ジャンプを強制できます。

test:
    jmp test         ; eb fb 
    jmp near test    ; e9 f6 ff ff ff

64 ビット アドレッシング モードには、RIP 相対、32 ビット絶対、64 ビット絶対、およびベース ポインターに対する相対があります。このJMP命令は、64 ビット絶対を除くこれらすべてを使用できます。間接ジャンプは Opcode を使用しますFF。NASM 構文を使用したいくつかの例:

jmp [a]                ;ff 24 25 00 00 00 00 - 32-bit absolute 
jmp [rel a]            ;ff 25 e7 ff ff ff    - RIP + 32-bit displacement
jmp [rdi]              ;ff 27                - base pointer
jmp [rdi +4*rsi + a]   ;ff a4 b7 00 00 00 00 - base pointer +4*index + displacement

ただし、OSX では、イメージのベースが 2^32 より大きいため、32 ビットの絶対アドレス指定はできません

64 ビットの絶対アドレッシングを使用できる唯一の命令は でmovあり、ソースまたは宛先のいずれかが である必要がありますAL, AX, EAX or RAX。例えばNASMで

mov rax, [qword a]
于 2014-11-17T10:56:22.767 に答える