2012-02-19 8 views
1

i386を例として考えてみましょう。しかし、類似の質問は他のアーチにも当てはまります。伝統的なi386 jmp_bufsetjmpによって保存され、ebx,esi,edi,ebp,espおよびeipの6つの保存されたレジスタで構成されています。これらのうち、最初の4つはABIごとに呼び出し元によって保存されているため、setjmpという関数はそれ自身の保存された値で上書きされます(setjmpの最初と2番目の戻り値の間で変更される可能性があります)。したがって、jmp_bufのこれらのレジスタを保存する際のポイントは何ですか?スタックと命令ポインタだけを保存するだけではうまくいかないでしょうか?setjmpは伝統的にレジスタを保存するのはなぜですか?

編集:私は誤って混乱の源であった発信者保存と呼び出し先保存を混同していました。みんなの時間を無駄にすることに対する謝罪。

+0

私たちはどのコンパイラとOSについて話していますか? –

答えて

4

setjmp/longjmpのペアは "goto"ではなく、 "セーブステート/リストアステート"のコンボです...ほとんどのレジスタが保存されていなければ、これはできません。例外はサブルーチンの戻りレジスタなので、setjmpへの通常の呼び出しから戻ったか、longjmp経由で戻ったかを識別できます。

編集 - あなたは質問4は、呼び出し側が保存されることになっているが、setjmp関数()あなたを信頼するつもりはない...そして、関係なく、あなたが何をしたかの正しいことをするつもりだ。)

+0

しかし、呼び出し元で保存されたレジスタの値は、少なくとも私が識別できるどのような観測可能な方法でも、状態の一部ではありません。復元された値は、 'setjmp'が復帰した後、しかしそれらが読まれる前にぎっしり詰まってしまいます。これは私の質問についてです。 –

+1

@R - 呼び出し元がC(または同じABIに従う他の高水準言語)で書かれているかのように見ていますが、setjmpはそれを仮定する余裕がありません。呼び出し元がアセンブリで記述されている場合、すべてのベットはオフです。 – mah

+0

'setjmp'はC言語の一部です。もしあなたがasmを書いているのであれば、それはCの範囲外ですが、Cの関数を呼び出すなら、あなたが扱っているABIの呼び出し規約を仮定しなければなりません。 –

0

setjumpはこれらの値を上書きすると仮定していますが、それはできるとは思えません。longjmpターゲットが不安定になり、使用不可能になるからです。

がときlongjmp戻っebxは、setjmpに入ることでポインタを持っていたと言うことができます、そのポインタ私たちは、このように非ローカルのgotoの全体のポイントを破って、素敵な例外を取得する可能性があります他に、復元する必要があります。

MSVCR100._setjmp3 7>MOV EDX,DWORD PTR SS:[ESP+4] 
73A030C4   MOV DWORD PTR DS:[EDX],EBP 
73A030C6   MOV DWORD PTR DS:[EDX+4],EBX 
73A030C9   MOV DWORD PTR DS:[EDX+8],EDI 
73A030CC   MOV DWORD PTR DS:[EDX+C],ESI 
73A030CF   MOV DWORD PTR DS:[EDX+10],ESP 
73A030D2   MOV EAX,DWORD PTR SS:[ESP] 
73A030D5   MOV DWORD PTR DS:[EDX+14],EAX 
73A030D8   MOV DWORD PTR DS:[EDX+20],56433230 
73A030DF   MOV DWORD PTR DS:[EDX+24],0 
73A030E6   MOV EAX,DWORD PTR FS:[0] 
73A030EC   MOV DWORD PTR DS:[EDX+18],EAX 
73A030EF   CMP EAX,-1 
73A030F2   JNZ SHORT MSVCR100.73A030FD 
73A030F4   MOV DWORD PTR DS:[EDX+1C],-1 
73A030FB   JMP SHORT MSVCR100.73A03138 
73A030FD   MOV ECX,DWORD PTR SS:[ESP+8] 
73A03101   OR ECX,ECX             ; Switch (cases 0..8) 
73A03103   JE SHORT MSVCR100.73A0310F 
73A03105   MOV EAX,DWORD PTR SS:[ESP+C] 
73A03109   MOV DWORD PTR DS:[EDX+24],EAX 
73A0310C   DEC ECX 
73A0310D   JNZ SHORT MSVCR100.73A03117 
73A0310F   MOV EAX,DWORD PTR DS:[EAX+C]         ; Cases 0,1 of switch 73A03101 
73A03112   MOV DWORD PTR DS:[EDX+1C],EAX 
73A03115   JMP SHORT MSVCR100.73A03138 
73A03117   MOV EAX,DWORD PTR SS:[ESP+10] 
73A0311B   MOV DWORD PTR DS:[EDX+1C],EAX 
73A0311E   DEC ECX 
73A0311F   JE SHORT MSVCR100.73A03138 
73A03121   PUSH ESI 
73A03122   PUSH EDI 
73A03123   LEA ESI,DWORD PTR SS:[ESP+1C] 
73A03127   LEA EDI,DWORD PTR DS:[EDX+28] 
73A0312A   CMP ECX,6 
73A0312D   JBE SHORT MSVCR100.73A03134 
73A0312F   MOV ECX,6             ; Default case of switch 73A03101 
73A03134   REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]    ; Cases 3,4,5,6,7,8 of switch 73A03101 
73A03136   POP EDI 
73A03137   POP ESI 
73A03138   SUB EAX,EAX             ; Case 2 of switch 73A03101 
73A0313A   RETN 

更新

それが保持しなければならないと述べstandards documentがあります:

より実用的な外観を取る、我々はそれらを保存する前に、MS CRTのレジスタは汚染されていないことがわかります環境:

setjmp()を呼び出すと、env argに呼び出し環境が保存されます。 longjmp()で後で使用できるようにします。

関連する問題