1. ホーム
  2. assembly

[解決済み] callq命令とは何ですか?

2022-01-28 16:13:37

質問内容

あるツールで生成された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 near命令とfar命令が書かれているだけです。

gnuアセンブラのドキュメントを見てみました。 https://sourceware.org/binutils/docs/as/index.html が、サポートしている命令の詳細が書かれている箇所は見つかりませんでした。

関数の呼び出しであることは理解できましたが、詳細を知りたいです。どこにあるのでしょうか?

どのように解決するのですか?

それは、ただ call . Intel/AMD マニュアルの命令を調べられるようにするには、Intel-syntax disassembly を使用します。

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

32ビットモードと64ビットモードでは、ツールによって違いがあります。( ゴッドボルト )

  • gcc -S: 常に call / ret . いいね
  • clang -S: callq / retqcalll / retl . 少なくとも一貫して迷惑な話だ。
  • objdump -d: callq / retq (明示的な64ビット)と call / ret (32ビットでは暗黙の了解)。 64ビットではオペランドサイズを選択できませんが、32ビットでは選択できるので、一貫性がなく、ちょっと間抜けです。 (ただし 有用な を選択することができます。 callw はEIPを16ビットに切り捨てています)。

    一方、REX.W のプレフィックスを付けない場合のデフォルトのオペランドサイズは、0.5mm です。 最も 64ビットモードでの命令は、依然として32です。 しかし add $1, (%rdi) オペランドサイズのサフィックスが必要で、何も指定しないとアセンブラは32ビットを選択しません。 一方 push は暗黙のうちに pushq であるにもかかわらず pushw $1pushq $1 はどちらもエンコード可能です ( であり、実際に使用可能な ) を64ビットモードで実行します。


インテルのインストラクションセット・レフ・マニュアル(上記リンク先)より。

ニアコール・アブソリュートでは、汎用レジスタまたはメモリ位置(r/m16、r/m32、r/m64)に間接的に絶対オフセットを指定する。 operand-size属性は、対象となるオペランドのサイズ(16、32、64ビット)を決定します。 64ビットモードの場合、近接呼び出し(およびすべての近接分岐)のオペランドサイズは64ビットに強制される .

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

32ビットモードでは、16ビットのエンコーディングが可能です。 call rel16 でEIPを16ビットに切り詰めたもの、あるいは call r/m16 は、16ビットの絶対的なアドレスを使用します。 しかし、マニュアルにあるように、64ビットモードではオペランドサイズは固定です。