我一直在試圖找到OCaml調用約定,以便我可以手動解釋gdb無法解析的堆棧跟蹤。不幸的是,除了一般的觀察外,似乎從來沒有人用英文寫下過。例如,人們會評論OCaml在寄存器中傳遞許多參數的博客。 (如果有英文文檔,鏈接將不勝感激。)OCaml調用約定:這是一個精確的總結嗎?
所以我一直試圖從ocamlopt源頭中解開它。任何人都可以確認這些猜測的準確性嗎?
而且,如果我對正在傳入寄存器的前十個參數是正確的,那麼通常不可能將參數恢復到函數調用?在C中,參數仍然會被推到堆棧的某個地方,如果只是我回到正確的框架。在OCaml中,被調用者似乎可以自由地摧毀他們的調用者的論點。
寄存器分配(從/asmcomp/amd64/proc.ml
)
對於調用到OCaml的功能,
- 第一10個整數和指針參數被在寄存器RAX,RBX,RDI,RSI傳遞,rdx,rcx,r8,r9,r10和r11
- 前10個浮點參數傳遞到寄存器xmm0 - xmm9
- 將其他參數壓入堆棧(最左邊的第一個?),魚漂和整數和指針混合
- 陷阱指針(見下文例外)中R14
- 的分配指針(據推測爲如本blog post描述的次要堆被傳遞)中R15
- 的被傳遞如果返回值是一個整數或指針,則返回rax;如果是浮點數,返回值返回xmm0
- 所有寄存器都是調用者保存的?
對於調用到C函數,標準AMD64 C約定用於:
- 前六個整數和指針參數在RDI,RSI,RDX,RCS,R8和R9 傳遞
- 前八個浮動參數在XMM0通過 - XMM7
- 附加參數被壓入堆棧
- 返回值是在RAX傳遞迴或XMM0 個
- 寄存器RBX,RBP,和R 12 - R 15是被調用者保存
返回地址(從/asmcomp/amd64/emit.mlp
)
返回地址被第一指針與推入呼叫幀中,根據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...)
身體某處,有一個線性化的操作碼Lraise
這是精確組裝發出:
movq %r14, %rsp
popq %r14
ret
這真的很整潔!我們不是創建setjmp/longjmp業務,而是創建一個虛擬框架,其返回地址是異常處理程序,其唯一本地是前一個虛擬框架。 /asmcomp/amd64/proc.ml
有一個註釋,稱$ r14爲「陷阱指針」,所以我將這個僞幀稱爲陷阱幀。當我們想要引發異常時,我們將堆棧指針設置爲最近的陷阱幀,在此之前將陷阱指針設置爲陷阱幀,然後「返回」到異常處理程序中。我敢打賭,如果異常處理程序不能處理這個異常,它只是重新評估它。
異常在%eax中。