2015-12-11 19 views
8

私は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);

、これがあるとして動作することはできません。実際、と入力すると、envvalにポインタを保持するために、rdirsiが既に詰まっています。同じことがrdiに関してlong_jmpに適用されます。

GCCを強制する方法はありますか?いくつかの属性に依存することによって、引数をスタック経由で強制的に渡すことができますか?これは、set_jmplong_jmpをラップするよりもはるかにエレガントになります。これは、後で取り出すために、スタック上のクローンされたレジスタを手動でプッシュするものです。

+1

これはPCS/ABIを壊すでしょう。あなたは間違った側から近づいています。あなたのアセンブラコードはABIに従わなければなりません。インラインアセンブラでC関数を直接使用するか、実際のコード用のラッパーとして使用するのが最善です。そうすれば、コードクローバーを登録する/メモリを指定するだけで、gccに保存/復元することができます。 – Olaf

+2

'setjmp'は' rdi'と 'rsi'を保存する必要はありません。あなたが言うように、それらは' setjmp'の中に詰まっています。実際には、 "callee-saved"(すなわち、rbp、ebx、r12、r13、r14、r15、もちろんrsp)としてマークされたレジスタだけを保存しなければなりません。 – fuz

+0

私はABIを尊重していないと同意しますが、それには理由があります。 'setjmp'によってセーブされないものは、呼び出し側がセーブレジスタとして扱うので、必要に応じて実際にセーブされますので、' setjmp'と 'longjmp'ですべてうまく動作します。私のアプリケーションでは、私はLinuxカーネルとのやりとりをしています。これは、ある割り込みで、ユーザーレベルのコードの別の部分に制御を戻し、次に、 'setjmp'を呼び出します。この構造により、もともと実行中のコードは 'setjmp'が呼び出されていることを知らないので、呼び出し側保存レジスタも同様に保存する必要があります。 – ilpelle

答えて

2

インラインアセンブリを使用して関数を呼び出して、レジスタを上書きすることを避けることができます。

#include <stdio.h> 

static void foo(void) 
{ 
     int i; 
     asm volatile ("mov 16(%%rbp), %0" : "=g" (i)); 
     printf("%d\n", i); 
} 

#define foo(x) ({ int _i = (x); \ 
     asm ("push %0\ncall %P1\nadd $8, %%rsp\n" : : "g"(_i), "i"(foo)); }) 

int main(int argc, char *argv[]) 
{ 
     foo(argc-1); 
     return 0; 
} 

ここで、整数がスタックにプッシュされ、関数fooが呼び出されます。 fooはローカル変数iで値を使用可能にします。戻った後、スタックポインタは元の値に調整されます。

+1

これはもちろん、呼び出し元の関数 'main()'フレームポインタとして '%rbp'を使用しているのではなく、それを余分な整数レジスタとして使用するか、プッシュ/ポップのオーバーヘッドを避けるために全く使用しません。後者は、 '-O2'でコンパイルすると実際にこのコードで起こるものです。 –

+0

@NateEldredge:それはひどく設計された 'foo'だけですが、彼の例のためのプレースホルダです。カスタムABIコールを生成するマクロはうまくいきます。 OPは、ASMで手書きされたカスタムの 'setjmp'実装を使用します。これは、これらの前提を何もしません。いくつかのレジスタをプッシュしてスクラッチ・レギュレーションを取得し、次にすべての呼び出し元の状態を保存することから始めます。 'xsave'がユーザー空間からうまく機能するかどうかをIDKで指定します。 –

関連する問題