2012-07-04 14 views
19

मैं ओकैमल कॉलिंग सम्मेलन को खोजने की कोशिश कर रहा हूं ताकि मैं मैन्युअल रूप से स्टैक निशान की व्याख्या कर सकूं जो gdb पार्स नहीं कर सकता है। दुर्भाग्यवश, ऐसा लगता है कि सामान्य अवलोकनों को छोड़कर अंग्रेजी में कभी भी कुछ भी लिखा नहीं गया है। उदाहरण के लिए, लोग ब्लॉग पर टिप्पणी करेंगे कि ओकैमल रजिस्टरों में कई तर्क पारित करता है। (यदि वहां कहीं भी अंग्रेजी दस्तावेज है, तो एक लिंक की बहुत सराहना की जाएगी।)ओकैमल कॉलिंग सम्मेलन: क्या यह एक सटीक सारांश है?

तो मैं इसे ओकंप्लोप स्रोत से बाहर निकालने की कोशिश कर रहा हूं। क्या कोई इन अनुमानों की सटीकता की पुष्टि कर सकता है?

और, यदि मैं रजिस्टरों में पारित किए गए पहले दस तर्कों के बारे में सही हूं, तो क्या फ़ंक्शन कॉल में तर्कों को पुनर्प्राप्त करना आम तौर पर संभव नहीं है? सी में, तर्क अभी भी ढेर पर धकेल दिए जाएंगे, अगर मैं केवल सही फ्रेम पर वापस चला जाता हूं। ओकैमल में, ऐसा लगता है कि कॉलर अपने कॉलर्स के तर्कों को नष्ट करने के लिए स्वतंत्र हैं।


रजिस्टर आवंटन (/asmcomp/amd64/proc.ml से) OCaml कार्यों में बुला लिए

,

  • पहले 10 पूर्णांक और सूचक तर्क रजिस्टरों Rax, Rbx, RDI, RSI में पारित कर रहे हैं , rdx, rcx, r8, r9, r10 और r11
  • रजिस्ट्रार xmm0 - xmm9
  • में पहले 10 फ़्लोटिंग-पॉइंट तर्क पारित किए गए हैं
  • अतिरिक्त तर्क स्टैक पर धकेल दिए जाते हैं (बाएं सबसे पहले-इन-इन?), तैरता और ints और संकेत
  • जाल सूचक (नीचे दिए गए अपवाद देखें) R14
  • आवंटन सूचक (संभवतः नाबालिग ढेर इस blog post में वर्णित के रूप में पारित हो जाता है) R15
  • का इन पारित हो जाता है intermixed वापसी मूल्य वापस रैक्स में पारित किया जाता है यदि यह एक पूर्णांक या सूचक है, और xmm0 में यह एक फ्लोट
  • सभी रजिस्ट्रार कॉलर-सेव हैं?

सी कार्यों में बुला लिए, मानक amd64 सी सम्मेलन प्रयोग किया जाता है:

  • पहले छह पूर्णांक और सूचक तर्क RDI, RSI, RDX, आरसीएस, R8, और r9
  • में पारित कर रहे हैं
  • पहले आठ नाव तर्क xmm0 में पारित कर रहे हैं - xmm7
  • अतिरिक्त तर्क ढेर
  • वापसी मान वापस Rax में पारित हो जाता है या xmm0
  • पर धकेल दिया जाता है
  • रजिस्टरों Rbx, RBP, और r12 - R15 हैं कॉल प्राप्त करने वाला-बचाने

वापसी पता (/asmcomp/amd64/emit.mlp से)

वापसी पता पहले सूचक के साथ कॉल फ्रेम में धकेल दिया जाता है अनुसार, amd64 सी सम्मेलन। (मुझे अनुमान है कि ret निर्देश इस लेआउट को मानता है।)

अपवाद (/asmcomp/linearize.ml से)

कोड try (...body...) with (...handler...); (...rest...) इस तरह linearized हो जाता है:

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

यह एक प्रश्न से अधिक उत्तर है! मुझे इस विषय पर थोड़ा सा पता है, मैंने आपके जैसे स्रोत को देखकर सीखा है, इसलिए उम्मीद नहीं है कि आगे की सटीकता आपकी पोस्ट की तुलना में अधिक आधिकारिक हो।

हां, मुझे लगता है कि ओकैमल केवल कॉलर-सेव रजिस्टरों के साथ विशेष कॉलिंग सम्मेलनों का उपयोग करता है। इस विकल्प का लाभ यह है कि यह पूंछ-कॉल को सरल बनाता है: जब आप पूंछ-कॉल के माध्यम से कूदते हैं, तो आपको किसी भी रजिस्टर को भरने या पुनः लोड करने की आवश्यकता नहीं होती है।

¹: गैर-स्वयं पूंछ कॉल के लिए, यह केवल तभी काम करता है जब बहुत अधिक तर्क नहीं होते हैं, और इसलिए हमें फैलाने की आवश्यकता नहीं होती है। यदि स्टैक आवंटन की आवश्यकता है, तो कॉल को गैर-पूंछ कॉल में बदल दिया जाता है।

ध्यान दें कि सम्मेलन कॉल करना अभी भी लक्षित वास्तुकला पर दृढ़ता से निर्भर करता है। उदाहरण के लिए x86 पर, रजिस्टरों को समाप्त होने पर और पूंछ-कॉल को संरक्षित करने के लिए स्टैक पर फैलाने से पहले ग्लोबल्स की एक छोटी संख्या का उपयोग किया जाता है।

मैं भी "वाम-पंथी-पहले में" इस बात से सहमत: तर्क, proc.ml में calling_conventions द्वारा क्रम में आगे बढ़ते जाते हैं emit.mlp में slot_offset की भरपाई क्रम में संग्रहित किया; वे जहां दाएं से बाएं गणना की गई, लेकिन selectgen.ml में क्रम में लौट आईं।

4

हां, आप कॉल से तर्क पुनर्प्राप्त नहीं कर सकते हैं, क्योंकि ओकैमल जितना संभव हो सके रजिस्टरों का पुन: उपयोग करने का प्रयास करता है, और इस प्रकार उनकी सामग्री को नष्ट कर देगा यदि यह किसी फ़ंक्शन के शेष में उपयोगी नहीं है। डिबगर्स के पास तर्क मुद्रित करने का कोई तरीका नहीं है, वे केवल फ़ंक्शन में दिए गए बिंदु पर, वेरिएबल को प्रिंट कर सकते हैं, लेकिन इसके लिए, आपको मूल्यों को पुनर्प्राप्त करने के लिए DWARF कोड को डंप करने के लिए ओकंप्लोप को संशोधित करने की आवश्यकता होगी।

संबंधित मुद्दे