c++ - अगर मैं एक डीएलएल में एक समारोह कॉल करते समय पर्याप्त पैरामीटर नहीं पारित करते हैं, तो क्या होगा?



dll (1)

32-बिट

डिफ़ॉल्ट कॉलिंग सम्मेलन __cdecl , जिसका अर्थ है कि कॉलर ने दायां-से-बाएं स्टैक पर मापदंडों को धक्का दिया है, फिर कॉल रिटर्न के बाद स्टैक को साफ करता है।

तो आपके मामले में, कॉलर:

  1. धक्का ब
  2. एक को धक्का
  3. रिटर्न पता धक्का
  4. फ़ंक्शन को कॉल करता है

इस बिंदु पर स्टैक इस तरह दिखता है (उदाहरण के लिए 4 बाइट पॉइंटर्स मान लें, और याद रखें कि स्टैक पॉइंटर आपकी चीज़ों को पुश करते समय पीछे की ओर जाता है):

+-----+ <--- this is where esp is after pushing stuff
| ret | [esp]
+-----+
|  a  | [esp+4]
+-----+
|  b  | [esp+8]
+-----+ <--- this is where esp was before we started
| ??? | [esp+12 and beyond]
+-----+

ठीक है अच्छा है। अब समस्या कैली पक्ष पर होती है कैली स्टैक पर कुछ स्थानों पर पैरामीटर की अपेक्षा कर रहा है, इसलिए:

  • a को [esp+4] पर माना जाता है
  • b को [esp+8] पर माना जाता है
  • c [esp+12] पर माना जाता है

और यह वह जगह है जहां यह मुद्दा है: हमें नहीं पता है कि [esp+12] क्या है तो बछड़े को a और b के सही मूल्यों को देखेंगे, लेकिन जो भी अज्ञात कचरा [esp+12] को c रूप में होता है, वह व्याख्या करेगा।

उस समय यह बहुत ज्यादा अनिर्भावित है, और यह निर्भर करता है कि आपके फ़ंक्शन वास्तव में c साथ क्या होता है।

यह सब खत्म होने के बाद और कैली रिटर्न, यह मानते हुए कि आपका प्रोग्राम क्रैश नहीं हुआ है, कॉलर विशेष रूप से पुनर्स्थापित करेगा और स्टैक पॉइंटर वापस हो जाएगा जहां यह होना चाहिए। इसलिए कॉलर की पीओवी से सबकुछ ठीक है और स्टैक पॉइंटर वापस समाप्त होता है जहां यह माना जाता है, लेकिन कैली c लिए जंक देखता है।

64-बिट

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

  • रजिस्टरों rcx , rdx , r8 , और r9 9 में पहले चार पूर्णांक या पॉइंटर r9 , उस क्रम में, बाएं से दाएं।
  • उस क्रम में, बाएं से xmm0 , रजिस्टरों में xmm0 , xmm1 , xmm2 और xmm3 में पहले चार फ़्लोटिंग-पॉइंट तर्क दिए गए हैं।
  • बाकी कुछ भी स्टैक पर धकेल दिया जाता है, दाएं-से-बाएं।
  • कॉलर esp बहाल करने के साथ-साथ कॉल के बाद सभी वाष्पशील रजिस्टरों के मूल्यों को पुनर्स्थापित करने के लिए जिम्मेदार है।

तो आपके मामले में, कॉलर:

  1. आरसीएक्स में a डालता a
  2. rdx में b डालता है।
  3. स्टैक पर "छाया स्पेस" के अतिरिक्त 32 बाइट को आवंटित करता है (देखें कि एमएस लेख)।
  4. रिटर्न पता धक्का।
  5. फ़ंक्शन को कॉल करता है

लेकिन कैली उम्मीद कर रहा है:

  • a rcx में माना जाता है (चेक!)
  • b को rdx (चेक!) में माना जाता है
  • c माना जाता है r8 (समस्या)

और इसलिए, 32-बिट मामले के साथ, कैली c रूप में r8 में जो कुछ भी हुआ है, और संभावित प्रभाव के साथ अंतिम प्रभाव के साथ, कैलोरी c साथ क्या होता है, इसका व्याख्या करता है। जब यह रिटर्न देता है, प्रोग्राम को क्रैश नहीं किया जाता है, तो कॉलर सभी वाष्पशील रजिस्टरों को पुनर्स्थापित करता है ( rcx और rdx , और आम तौर पर r8 और दोस्तों को भी शामिल होता है) और esp पुनर्स्थापित करता है

डीएलएल प्रोजेक्ट में, फ़ंक्शन इस तरह है:

extern "C" __declspec(dllexport) void foo(const wchar_t* a, const wchar_t* b, const wchar_t* c)

एक अलग परियोजना में, मैं foo फ़ंक्शन का उपयोग करूँगा, लेकिन मैं हेडर फाइल में foo फ़ंक्शन को घोषित करता हूँ

extern "C" __declspec(dllimport) void foo(const wchar_t* a, const wchar_t* b)

और मैं इसे केवल दो मापदंडों के साथ कहता हूं।

परिणाम सफलता है, मुझे लगता है कि यह __cdecl कॉल के बारे में है, लेकिन मैं यह जानना चाहूंगा कि यह कैसे और क्यों काम करता है।





dll