2012-07-04 23 views
19

OCaml çağrı kuralını bulmaya çalışıyorum, böylece gdb'nin ayrıştırılamadığı yığın izlerini elle yorumlayabiliyorum. Maalesef, genel gözlemler haricinde İngilizce'de hiçbir şey yazılmamış gibi görünüyor. Örneğin, insanlar, bloglarda OCaml'ın kayıtlardaki birçok argümanı geçtiğini söyleyecektir. (Bir yerde İngilizce belgeleri varsa, bir bağlantı çok takdir edilecektir.)OCaml çağrı kuralı: Bu doğru bir özet midir?

Ocamlopt kaynağından çıkarmaya çalışıyorum. Bu tahminlerin doğruluğunu herkes onaylayabilir mi?

Ve eğer ilk on argüman hakkında kayıtlara geçtiysem haklıysam, argümanları genelde bir işlev çağrısına kavuşturmak mümkün olmaz mı? C'de, argümanlar hala bir yere doğru itilirdi, eğer sadece doğru çerçeveye geri dönersem. OCaml'da, kandillerin arayanlarının argümanlarını yok etmekte özgür oldukları görülüyor. ilk 10 tam sayı ve işaretçi argümanlar kayıt rax, RgX RDI, RSI geçirilir

  • , OCaml işlevlerini çağrı için

    (/asmcomp/amd64/proc.ml den)


    Kayıt ayırma rxx, rcx, r8, r9, r10 ve r11

  • İlk 10 kayan nokta argümanı, xmm0 - xmm9
  • kayıtlarından geçirilir.
  • Ek argümanlar yığının üzerine itilir (En soldaki ilk giren?), mantarlar ve int ve işaretçiler
  • tuzak işaretçi (aşağıdaki İstisnalar bakınız) muhtemelen bu blog post tarif edildiği gibi küçük yığın için R14
  • ayırma işaretçi (geçirilen) R15
  • The geçirilir karışmış bir tamsayı veya işaretçi ise, dönüş değeri geri döndürülürse ve xmm0'de bir float varsa
  • Tüm kayıtlar arayan kaydedicidir? Cı işlevlerini çağrı için

, standart amd64'tür Cı kuralı kullanılır:

  • ilk altı tam sayı ve işaretçi argümanlar RDI, RSI, RDX RCS, R8 ve R9'un hiçbirinin
  • geçirilir
  • ilk sekiz yüzer argümanlar xmm0 geçirilir - xmm7
  • ek bağımsız değişkenler yığın bir dönüş değeri rax Lütfen geçirilir
  • veya xmm0
  • itilir
  • kayıt, RBP rbx ve R12 - tasarrufu Aranan R15

gönderici adresi birinci işaretçi uygun olarak, çağrı çerçeve içine itilir

(/asmcomp/amd64/emit.mlp gelen) geri adresi amd64 C sözleşmesi. (Ben tahmin ediyorum ret talimat bu düzeni varsayar./asmcomp/linearize.ml itibaren)

İstisnalar()

kod try (...body...) with (...handler...); (...rest...) böyle doğrusallaştırılmış alır: Sağdaki (hedefleri)

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

ve sonra böyle montaj olarak yayılan:

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

Vücudun herhangi bir yerinde doğrusal bir opcode var Lraise, bu tam montaj olarak gönderilir:

movq %r14, %rsp 
popq %r14 
ret 

Gerçekten temiz! Bu setjmp/longjmp iş yerine, dönüş adresi istisna işleyicisi olan ve yalnızca yerel olan önceki bu kukla çerçeve olan bir kukla çerçeve oluşturuyoruz. /asmcomp/amd64/proc.ml, "trap işaretçisi" $ r14'ü arayarak bir yorum içerir, bu yüzden bu kukla çerçeveyi tuzak çerçevesine çağıracağım. Bir istisnayı yükseltmek istediğimizde, yığın işaretçisini en son tuzak çerçevesine ayarlıyoruz, tuzak işaretçisini bundan önceki tuzak çerçevesine ayarlıyoruz ve sonra istisna eylemciye "geri dönüyoruz". Ve bahse girerim, istisna eylemcisi bu istisnayı kaldıramazsa, sadece yeniden değerlendirir.

İstisnası% eax.

cevap

6

Bu, bir sorudan daha çok bir cevaptır! Bu konuda bildiklerim, tıpkı sizin gibi, kaynağa bakarak öğrendim, bu yüzden daha fazla kesinleşmenin, görevinizden çok daha güvenilir olmasını beklemeyin.

Evet, OCaml'ın yalnızca arayanlar için kaydetme kayıtlarıyla özel arama kuralları kullandığını düşünüyorum. Bu seçeneğin bir yararı, kuyruk çağrılarını basitleştirmesidir: bir kuyruk aramadan geçtiğinizde, herhangi bir kaydı dökmeniz veya yeniden yüklemeniz gerekmez. 12: Özgün olmayan aramalar için, bu yalnızca çok fazla argüman bulunmadığında çalışır ve bu nedenle dökülmemize gerek yoktur. Yığın tahsisine gerek duyulursa, arama kuyruk olmayan bir aramaya dönüştürülür.

Arama kurallarının hala hedef mimariye bağlı olduğunu unutmayın. Örneğin, x86 üzerinde, yazmaçların tükenmesi ve yığına dökülmeden önce kuyruk çağrılarını korumak için az sayıda globals kullanılır.

Ben de "en soldaki birinci-in" üzerinde anlaşma: argümanlar emit.mlp yılında slot_offset tarafından ofset sırayla depolanır, proc.ml yılında calling_conventions tarafından sırayla varolmaktadırlar; selectgen.ml içinde sağdan sola hesaplanan, ancak sırayla döndürülenler.

4

Evet, bir çağrının argümanlarını geri yükleyemezsiniz, çünkü OCaml mümkün olduğunca çok sayıda dosyayı yeniden kullanmayı dener ve böylece bir işlevin geri kalanında artık yararlı değilse, içeriğini yok eder. Hata ayıklayıcıları argümanları basmanın bir yolu yoktur, bunlar yalnızca işlevin belirli bir noktasında, hala canlı değişkenleri basabilir, ancak bu değerleri kurtarmak için DWARF kodunu dökmek için ocamlopt'u değiştirmeniz gerekir.