私はsetjmp
/longjmp
CPUの全体的なコンテキスト(つまり、すべてのxmm、fpuスタックなど)を保存するx86-64システム用のカスタム実装呼び出し先保存レジスタ)。これはアセンブリに直接書き込まれます。x86_64:スタック上の引数をgccに渡すようにする
コードは、最小限の例(アセンブリソースから直接呼び出すとき)で正常に動作します。この問題は、パラメータが自作setjmp
/longjmp
関数に渡される方法のために、Cコードで使用するときに発生します。実際、x64_64システム用のSysV ABIは、引数がレジスタを介して渡されるべきであると指示します(最大6の場合)。私の関数のシグネチャは以下のとおりです。もちろん
long long set_jmp(exec_context_t *env);
__attribute__ ((__noreturn__)) void long_jmp(exec_context_t *env, long long val);
、これがあるとして動作することはできません。実際、と入力すると、env
とval
にポインタを保持するために、rdi
とrsi
が既に詰まっています。同じことがrdi
に関してlong_jmp
に適用されます。
GCCを強制する方法はありますか?いくつかの属性に依存することによって、引数をスタック経由で強制的に渡すことができますか?これは、set_jmp
とlong_jmp
をラップするよりもはるかにエレガントになります。これは、後で取り出すために、スタック上のクローンされたレジスタを手動でプッシュするものです。
これはPCS/ABIを壊すでしょう。あなたは間違った側から近づいています。あなたのアセンブラコードはABIに従わなければなりません。インラインアセンブラでC関数を直接使用するか、実際のコード用のラッパーとして使用するのが最善です。そうすれば、コードクローバーを登録する/メモリを指定するだけで、gccに保存/復元することができます。 – Olaf
'setjmp'は' rdi'と 'rsi'を保存する必要はありません。あなたが言うように、それらは' setjmp'の中に詰まっています。実際には、 "callee-saved"(すなわち、rbp、ebx、r12、r13、r14、r15、もちろんrsp)としてマークされたレジスタだけを保存しなければなりません。 – fuz
私はABIを尊重していないと同意しますが、それには理由があります。 'setjmp'によってセーブされないものは、呼び出し側がセーブレジスタとして扱うので、必要に応じて実際にセーブされますので、' setjmp'と 'longjmp'ですべてうまく動作します。私のアプリケーションでは、私はLinuxカーネルとのやりとりをしています。これは、ある割り込みで、ユーザーレベルのコードの別の部分に制御を戻し、次に、 'setjmp'を呼び出します。この構造により、もともと実行中のコードは 'setjmp'が呼び出されていることを知らないので、呼び出し側保存レジスタも同様に保存する必要があります。 – ilpelle