2013-10-15 4 views
5

実験用に自分のスタックを一時的に使用するコードを書いています。これは、リテラルのインラインアセンブリを使用したときに機能しました。私はebpのオフセットとして可変ロケーションをハードコーディングしていました。しかし、私は自分のコードがメモリアドレスをハードコードすることなく動作することを望んでいたので、GCCのEXTENDED INLINE ASSEMBLYを調べました。私が持っているものは、次のとおりです。

volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER; 
volatile intptr_t old_stack_ptr = 0; 
asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

これは、まずスタックポインタを変数old_stack_ptrに保存することです。次に、スタックポインタ(%esp)がnew_stack_ptrに保存したアドレスで上書きされます。

これにもかかわらず、GCCは%espをold_stack_ptrに保存していましたが、%espをnew_stack_ptrに置き換えていませんでした。より深い検査の際に、私はそれが実際に私のアセンブリを拡大し、それは以下の通りです自身の指示、です追加が見つかりました:

mov -0x14(%ebp),%eax 
mov %esp,%eax 
mov %eax,%esp 
mov %eax,-0x18(%ebp) 

私はそれが明示的として宣言されていないため、GCCは、ESP%を維持しようとしていると思います"出力"オペランド...私はこれで完全に間違っている可能性があります...

私は実際には、これを行うために拡張インラインアセンブリを使用したいと思います。 %ebpのアセンブリへのオフセット、そして私はむしろこれのような変数名を使うでしょう...特に、このコードはいくつかの異なるシステムで動作する必要があります。私は明白にすることができます変数の位置を言うと...しかし、私はそれが余分なものをやっている理由を理解していないと私は拡張アセンブリを使用して以来、それはこれをやって以来、それは以前のようにスタックポインタを上書きしないようにしていません。

何か助けていただきありがとうございます!

+0

これが役立つかどうかわかりませんが、 '-fomit-frame-pointer'(' -O1'以上で有効)は '%ebp'を心配する必要がなくなります。 – DaoWen

+0

デバッグ(最適化なし)ビルドを行っているため、GCCはデフォルトで潜在的なエラーをキャッチするため、余分なものはおそらく存在します。 "GCC Stack Frame Checks"を検索して、GCCが提供するオプションを確認してください。 – Skizz

答えて

8

問題はgccが同じレジスタに入出力を割り当てていることですeax。入力を使用する前に出力を壊しているとgccに伝えたいとします。 "earlyclobber"。

asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=&r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

出力には&記号があることに注意してください。これはあなたのコードを修正するはずです。

更新:「は、引数と同じレジスタにこれを入れると言う

asm __volatile__("xchg %%esp, %0\n\t" 
     : "=r"(old_stack_ptr) /* output */ 
     : "0"(new_stack_ptr) /* input */ 
     ); 

お知らせ"0":代わりに、あなたはそうのように、同じレジスタなるとxchgを使用するために、入力と出力を強制することができ0 "。

+0

ありがとうsoooo!私は前に早期の騒ぎを聞いたことはありません。優れた答え。ほんとうにありがとう。それはそれを修正した。 – Chad

+1

私は代わりに 'xchg'を使って、入力と出力が同じレジスタに入るようにすることもできます。 – Jester

関連する問題