2012-07-04 8 views
19

私はOCamlの呼び出し規約を調べて、gdbが解析できないスタックトレースを手作業で解釈できるようにしようとしています。残念ながら、一般的な観察以外は英語で書かれたことがないようです。たとえば、OCamlが多数の引数をレジスタに渡しているブログについて、人々はコメントします。 (もしどこか英語の文書があれば、リンクは非常に高く評価されます)。OCaml呼び出し規約:これは正確な要約ですか?

私はocamloptソースからそれを困惑させようとしています。誰もこれらの推測の正確さを確認できますか?

そして、最初の10個の引数がレジスタに渡されているとすれば、関数呼び出しの引数を回復することは一般的に不可能ですか? Cでは、正しいフレームまで戻ってくるだけで、引数はスタックのどこかにプッシュされます。 OCamlでは、呼び出し先は呼び出し元の引数を自由に破棄することができます。第10の整数とポインタ引数がレジスタRAX、RBX、RDI、RSIに渡され

  • 、OCamlの機能を呼び出すため

    /asmcomp/amd64/proc.mlから)


    レジスタ割り付け 、rdx、rcx、r8、r9、r10、r11

  • 最初の10個の浮動小数点引数は、xmm0 - xmm9レジスタに渡されます。
  • 追加の引数がスタックにプッシュされます(左端の最初の?)、浮遊およびint型とポインタがトラップポインタが(以下の例外を参照)、おそらくこのblog postで説明したように、マイナーヒープの割り当てポインタが()R15
  • に渡されR14
  • に渡される
  • を混在戻り値は、整数またはポインタの場合はraxに、浮動小数点の場合はxmm0に返されます。
  • すべてのレジスタは呼び出し側で保存されますか? C関数に呼び出すため

、標準AMD64のC規則が使用される:

  • 第6の整数とポインタ引数がRDI、RSI、RDX、RCS、R8、及びR9
  • に渡され
  • 最初の8つの浮動小数点引数はXMM0に渡される - xmm7
  • 追加の引数は、スタックの戻り値はRAXに戻され
  • またはXMM0
  • にプッシュされていますリターンアドレスがに従い、通話フレームに押し込ま最初のポインタであるR15ある呼び出し先保存

リターンアドレス/asmcomp/amd64/emit.mlpから)

から

  • レジスタは、RBPをRBX、そしてR12 amd64 Cのコンベンション。 (私はret命令がこのレイアウトを前提としていると推測しています。/asmcomp/linearize.mlから)

    例外()

    コードtry (...body...) with (...handler...); (...rest...)このような線状化されます:次に

    Lsetuptrap .body 
    (...handler...) 
    Lbranch .join 
    Llabel .body 
    Lpushtrap 
    (...body...) 
    Lpoptrap 
    Llabel .join 
    (...rest...) 
    

    このようなアセンブリとして放出(右側宛先):

    call .body 
    (...handler...) 
    jmp .join 
    .body: 
    pushq %r14 
    movq %rsp, %r14 
    (...body...) 
    popq %r14 
    addq %rsp, 8 
    .join: 
    (...rest...) 
    

    本文のどこかに線形化されたオペコードがありますこの厳密なアセンブリとして放出される:

    movq %r14, %rsp 
    popq %r14 
    ret 
    

    どちらが本当にすてきです!このsetjmp/longjmpビジネスの代わりに、戻りアドレスが例外ハンドラであり、そのローカルのみが前のそのようなダミーフレームであるダミーフレームを作成します。 /asmcomp/amd64/proc.mlに$ r14を "トラップポインタ"と呼んでいるコメントがあるので、このダミーフレームをトラップフレームと呼ぶことにします。例外を発生させたいときは、スタックポインタを最新のトラップフレームに設定し、その前にトラップポインタをトラップフレームに設定してから、例外ハンドラに「戻す」。また、例外ハンドラがこの例外を処理できない場合は、それを再評価します。

    例外は%eaxにあります。

  • 答えて

    6

    これは質問よりも答えです!私がこの話題で知っているビットは、あなたと同じようにソースを見て学んだので、あなたの投稿よりもはるかに高い精度を期待してはいけません。

    はい、私はOCamlが呼び出し元保存レジスタでのみ特殊な呼び出し規約を使用していると思います。この選択の利点は、テールコールを簡略化することです。テールコールを使いこなす場合は、登録を紛失または再ロードする必要はありません。

    ¹:非自己テールコールの場合、これはあまり引数がない場合にのみ機能するため、流出する必要はありません。スタック割り当てが必要な場合、コールは非テールコールに変換されます。

    呼び出し規約は、引き続きターゲットアーキテクチャに強く依存することに注意してください。例えばx86では、テールコールを保持するために、レジスタが使い果たされたときやスタックに流出する前に少数のグローバルが使用されます。

    私はまた、「一番左-ファーストイン」に同意:引数がproc.mlcalling_conventions順に横断され、emit.mlpslot_offsetによって相殺順に保存されています。右から左に計算されるが、順番に返される場合はselectgen.mlになります。

    4

    はい、コールから引数を回復することはできません.OCamlは可能な限りレジスタを再利用しようとします。したがって、関数の残りの部分でもう役に立たない場合、内容を破棄します。デバッガには引数を出力する方法がありません。関数内の指定された場所にしかまだ存在する変数を表示することはできませんが、値を回復するためにDWARFコードをダンプするようにocamloptを変更する必要があります。

    関連する問題