13

インラインアセンブリからC/C ++関数を呼び出したい場合は、次のようにすることができます。

void callee() {}
void caller()
{
    asm("call *%0" : : "r"(callee));
}

GCCは、次のようなコードを出力します。

movl $callee, %eax
call *%eax

間接呼び出しは古いCPUのパイプラインを破壊するため、これは問題になる可能性があります。

のアドレスは最終的に定数であるため、制約calleeを使用できると想像できます。iGCCオンラインドキュメントからの引用:

「私」

即値の整数オペランド(定数値を持つもの)が許可されます。これには、アセンブリ時以降にのみ値がわかるシンボリック定数が含まれます。

私がこのようにそれを使おうとすると:

asm("call %0" : : "i"(callee));

アセンブラから次のエラーが発生します。

エラー:`call'のサフィックスまたはオペランドが無効です

これは、GCCがコードを発行するためです

call $callee

それ以外の

call callee

だから私の質問は、GCC出力を正しくすることが可能かどうかですcall

4

4 に答える 4

14

私はGCCのメーリングリストから答えを得ました:

asm("call %P0" : : "i"(callee));  // FIXME: missing clobbers

%P0文書化されていない機能のように見えるので、実際に何を意味するのかを知る必要があります...

編集P:GCCソースコードを見た後、制約の前のコードが何を意味するのか正確にはわかりません。$ただし、特に、GCCが定数値の前にを置くことを防ぎます。この場合、まさにこれが必要です。


これを安全に行うには、関数呼び出しが変更する可能性のあるすべてのレジスタについてコンパイラに通知する必要があります: "eax", "ecx", "edx", "xmm0", "xmm1", ..., "st(0)", "st(1)", ...

インラインasmから関数呼び出しを正しく安全に行う完全なx86-64の例については、拡張インラインASMでのprintfの呼び出しを参照してください。

于 2010-08-13T09:56:12.473 に答える
2

たぶん私はここで何かが欠けていますが

extern "C" void callee(void) 
{

}

void caller(void)
{
  asm("call callee\n");
}

正常に動作するはずです。名前がC++の名前付けマングリング規則に基づいて装飾されないようにするには、extern"C"が必要です。

于 2016-01-13T13:13:07.973 に答える
0

32ビットコード(たとえば、-m32 gccオプション)を生成している場合、次のasmインラインは直接呼び出しを発行します。

asm ("call %0" :: "m" (callee));
于 2015-06-11T20:06:26.893 に答える
-1

秘訣は文字列リテラルの連結です。GCCがコードから実際の意味を取得しようとする前に、隣接する文字列リテラルを連結します。したがって、アセンブリ文字列はプログラムで使用する他の文字列と同じではありませんが、次の場合は連結する必要があります。

#define ASM_CALL(X) asm("\t call  " X "\n")


int main(void) {
    ASM_CALL( "my_function" );
    return 0;
}

GCCを使用しているので、

#define ASM_CALL(X) asm("\t call  " #X "\n")

int main(void) {
   ASM_CALL(my_function);
   return 0;
}

まだわからない場合は、インラインアセンブリから物事を呼び出すのは非常に難しいことに注意する必要があります。コンパイラが他の関数への独自の呼び出しを生成する場合、呼び出しの前後に設定と復元を行うためのコードが含まれています。しかし、それはあなたの呼び出しのためにこれのいずれかを行うべきであることを知りません。あなたはそれを自分で含める必要があります(正しく理解するのは非常にトリッキーで、コンパイラのアップグレードやコンパイルフラグで壊れることがあります)、またはレジスタや条件を変更していないように見えるように関数が記述されていることを確認してくださいスタック(またはその変数)。

編集これはC関数名に対してのみ機能します-マングルされているためC++では機能しません。

于 2010-08-12T15:39:16.833 に答える