2012-03-06 8 views
5

私はx86_64の割り込み処理ルーチンを書いています。 ABIは、C関数を呼び出す前に、スタックを16バイトに揃えなければならないと指定しています。 x86_64 ISAは、ISRへの入力時に、私のスタックが8バイトに整列することを指定します。私はスタックポインタを16バイトに合わせる必要があります。問題は私のC関数からの復帰時に、私は割り込みから正しく戻ることができるように(潜在的に)アンアラインドスタックポインタを回復する必要があるということです。x86_64スタックを整列し、レジスタを保存しないでリカバリします。

汎用レジスタを使わずにこれを行う方法があるのだろうか?

+0

ヒープにSPを格納していますか? –

+0

@ H2CO3それは恐ろしい考えのように聞こえる。この文脈でヒープの概念も持っていません。 – dschatz

+0

それはちょっとした気分だった。 –

答えて

8

はここに置かとして質問に対する私のソリューションです:

pushq %rsp 
pushq (%rsp) 
andq $-0x10, %rsp 
    call function 
movq 8(%rsp), %rsp 

2つのプッシュが(%rsp)8(%rsp)でそれがもともと持っていた同じアラインメント、および元%rspのコピーとスタックを残します。 andqはスタックを整列します。すでに16バイト整列されていた場合は何も変更されません.8バイト整列の場合は%rspから8を引いて、元の%rsp8(%rsp)16(%rsp)になります。したがって、無条件に復元することができます8(%rsp)から。

4

アライメント操作がrspレジスタを破壊しているため、追加のレジスタを必要としません。私は、追加のレジスタを使用せずにそれを行うための唯一の方法は、追加のレジスタを使用していない唯一のポイントになり、メモリへの追加書き込み、読み出しを必要と疑う

push %rbp   ;save rbp for stack pointer 
mov %rsp, %rbp ;move old sp to rbp 
and $-0x10, %rsp ;align stack 
...     
...    ;if you want to use %rbp here, save it on the stack before 
... 
mov %rbp, %rsp ;old stack pointer 
pop %rbp 
iret 
+0

あなたは私にそれが当てはまるとは思うが、方法がないと私に確信されていない。操作が破壊的であるという理由だけで、元のスタックポインタを保存するために整列する前に何かできないということを意味するわけではありません。 – dschatz

+0

さて、そこには1つの方法があります:あなたはスタックポインタを押してから、マジックナンバーをスタックすることができます。 64ビットアドレス空間のすべてのアドレスがx86_64で現在許可されているわけではないため、スタックアドレスではないマジックを選択することができます。帰ってくると、あなたは魔法を探して、それの後ろにあるスタックポインタを見つけます。アライメントされたスタックと古いスタックとの間のギャップにランダムなチャンスでマジックが含まれている場合、マジックが2回見つかるため、このケースを識別できます。 – hirschhornsalz

+0

'%rbp'を使うのが良い選択です。なぜなら、これはcallee-savedレジスタだからです(C関数は、それが壊れてしまうと、それを返す前に復元するでしょう)。 – caf

0

に沿って何かをする必要があります。

私の現在のソリューションを提供します。私はrbpを格納するので、一時的な格納に使用してから、関数の呼び出しの前に復元することができます。この説明している他の人のように%のEBPを使用するよりもおそらく遅く

movq %rbp, -24(%rsp) //store original rbp 3 words beyond the stack 
movq %rsp, %rbp //store original rsp 
subq $8, %rsp //buy a word on the stack 
andq $-0x10, %rsp //16 byte align the stack (growing downwards) 
//We now have 1 or 2 words free on the stack (depending on the original 
// alignment). This is why we put rbp 3 words beyond the stack 
movq %rbp, (%rsp) //store the original rsp right here 
movq -24(%rbp), %rbp //restore original rbp 
call foo 
movq (%rsp), %rsp //restore original rsp 
iretq 
+0

これはネストされた割り込みに対して安全ではありません。もし '-24(%rsp)'に格納した後、 '%rsp'を調整する前に優先度の高い割り込みがあなたに当たったら、あなたの保存した'%rbp'を壊すでしょう。 – caf

0

に答えるのをdrhirschに似ていますが、どの程度:

push %rsp 
    test $0xf, %rsp 
    jz aligned 
    push (%rsp) // duplicate the top of the stack 
aligned: 
    // now have 16-byte alignment with the original stack pointer 
    // on the top of the stack, either once or twice 
     : 
    pop %rsp 
    iret 

これはスタックがすでに8バイト整列であるという事実を利用しますプッシュ命令はメモリからプッシュされる値を読み取ることができることを理解されたい。

+0

これは条件付きプッシュですが、無条件ポップです。非常に問題があります。 –

+0

@R:なぜですか?無条件ポップは、スタックポインタを変更して、条件が何であってもスタックポインタを元に戻します。 –

+0

ああ、今私はそれを手に入れます。非常に賢い!私はそれが好きです。 –

関連する問題