私は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
から)
から
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にあります。