web-dev-qa-db-ja.com

callq命令とは何ですか?

ツールによって生成されたx86_64アーキテクチャ用のgnuアセンブラコードがいくつかあります。これらの手順があります。

movq %rsp, %rbp  
leaq str(%rip), %rdi
callq puts
movl $0, %eax

「callq」命令に関する実際のドキュメントが見つかりません。

http://support.AMD.com/TechDocs/24594.pdf 「AMD64 Architecture Programmer's Manual Volume 3:General-Purpose and System Instructions」ですが、近くのCALLと遠い指示。

私はgnuアセンブラーのドキュメントを見てきました https://sourceware.org/binutils/docs/as/index.html ですが、それがサポートする指示の詳細なセクションを見つけることができませんでした。

関数の呼び出しであることは理解していますが、詳細を知りたいと思います。どこで見つけることができますか?

23
user10607

call だけです。 Intel/AMDのマニュアルで指示を検索できるようにする場合は、Intel構文の逆アセンブリを使用します。

qオペランドサイズサフィックスは技術的に適用されます(64ビットのリターンアドレスをプッシュし、RIPを64ビットレジスタとして扱います)が、命令プレフィックスでそれをオーバーライドする方法はありません。つまり、calllcallwは64ビットモードではエンコードできないため、一部のAT&T構文ツールがcallqではなくcallと表示するのは面倒です。もちろん、これはretqにも当てはまります。

32ビットモードと64ビットモードでは、ツールが異なります。 ( ゴッドボルト

  • gcc -S:常にcall/ret。いいね.
  • clang -S:callq/retqおよびcalll/retl。少なくとも一貫して迷惑です。
  • objdump -d:callq/retq(明示的な64ビット)およびcall/ret(32ビットの暗黙的な)。 64ビットにはオペランドサイズの選択がありませんが、32ビットには選択肢があるため、一貫性がなく、ちょっと馬鹿げています。 (ただし、useful選択ではありません:callwはEIPを16ビットに切り捨てます。)

    一方、64ビットモードのmost命令のデフォルトのオペランドサイズ(REX.Wプレフィックスなし)は32です。しかし、add $1, (%rdi)には、オペランドサイズのサフィックス;アセンブラーが32ビットを選択することはありません。 OTOH、Pushは暗黙的にpushqです。ただし、pushw $1pushq $1は両方とも64ビットモードでエンコード可能です( および実際に使用可能 )。


Intelの命令セット参照マニュアル(上記にリンク):

ニアコールアブソリュートの場合、絶対オフセットは、汎用レジスタまたはメモリロケーション(r/m16、r/m32、またはr/m64)で間接的に指定されます。 operand-size属性は、ターゲットオペランドのサイズ(16、32、または64ビット)を決定します。 64ビットモードの場合、ニアコール(およびすべてのニアブランチ)のオペランドサイズは64ビットに強制されます

for rel32 ...絶対オフセットと同様に、operand-size属性はターゲットオペランドのサイズ(16、32、または64ビット)を決定します。 64ビットモードでは、オペランドのサイズが近い分岐に対して64ビットに強制されるため、ターゲットオペランドは常に64ビットになります。

32ビットモードでは、EIPを16ビットに切り捨てる16ビットcall rel16、または絶対16ビットアドレスを使用するcall r/m16をエンコードできます。しかし、マニュアルにあるように、オペランドサイズは64ビットモードで固定されています。

26
Peter Cordes

callqは、共有ライブラリ/動的ライブラリ内の再配置可能な呼び出しを指します。アイデアは0をプッシュし、次にシンボルをプッシュして検索し、関数を呼び出して、最初の呼び出しで検索します。プログラムの再配置可能テーブルでは、関数の最初の呼び出しで関数の実際の場所への呼び出しを置き換えます。後続の呼び出しは、実行時に作成された再配置テーブルを参照します。

0
Shawn Miller