インライン アセンブリで適切な引数を使用して関数ポインターを呼び出すことはそれほど問題にはならないはずですが、使用される呼び出し規約がおそらく異なるため (デフォルト32 ビットと 64 ビットの Linux では明らかに異なります)。詳細はこちらをご覧ください。したがって、この場合、インライン アセンブリなしで回避できれば (他の回答を参照)、移植が容易になると思います。
編集:OK、アセンブリを使用する必要があるかもしれません。ここにいくつかの指針があります。
Agner Fog のドキュメントによると、Linux x64 はパラメータ転送に RDI、RSI、RDX、RCX、R8、R9、および XMM0-XMM7 を使用します。これは、(浮動小数点の使用を無視して)目的を達成するために、関数が次のことを行う必要があることを意味します。
(1) 退避が必要なすべてのレジスター (RBX、RBP、R12-R15) を退避: スタック上のスペースを確保し、これらのレジスターをそこに移動します。これは (Intel 構文) の行に沿ったものになります。
sub rsp, 0xSomeNumber1
mov [rsp+i*8], r# ; insert appropriate i for each register r# to be moved
(2) ターゲット関数にスタックで渡さなければならない引数の数を評価します。sub rsp, 0xSomeNumber2
これを使用して、スタック ( ) に必要なスペースを確保し、スタック0xSomeNumber1
が最後に 16 バイトにアラインされるようにします。つまりrsp
、16 の倍数にする必要がありますrsp
。戻ってきた。
(3) 関数の引数をスタック (必要な場合) およびパラメーター転送に使用されるレジスターにロードします。私の見解では、スタック パラメーターから始めて、最後にレジスター パラメーターをロードするのが最も簡単です。
;loop over stack parameters - something like this
mov rax, qword ptr [AddrOfFirstStackParam + 8*NumberOfStackParam]
mov [rsp + OffsetToFirstStackParam + 8*NumberOfStackParam], rax
ルーチンの設定方法によっては、最初のスタック パラメータなどへのオフセットが不要になる場合があります。次に、レジスタに渡される引数の数を設定します (必要のない引数はスキップします)。
mov r9, Param6
mov r8, Param5
mov rcx, Param4
mov rdx, Param3
mov rsi, Param2
mov rdi, Param1
(4) 上記とは別のレジスタを使用して対象関数を呼び出します。
call qword ptr [r#] ; assuming register r# contains the address of the target function
(5) 保存されたレジスタを復元rsp
し、関数へのエントリ時の値に復元します。必要に応じて、呼び出された関数の戻り値を必要な場所にコピーします。それで全部です。
注: 上記のスケッチは、XMM レジスタで渡される浮動小数点値を考慮していませんが、同じ原則が適用されます。
免責事項: Win64 で同様のことを行ったことはありますが、Linux では行ったことがないため、見落としている詳細がいくつかある可能性があります。よく読んで、コードを注意深く書き、よくテストしてください。