2013-03-03 10 views
7

(मुझे लगता है कि इस प्रश्न का एक बड़ा मौका या तो डुप्लिकेट है या अन्यथा यहां पहले ही उत्तर दिया गया है, लेकिन उत्तर की तलाश करना "स्टैक आवंटन" और संबंधित शर्तों से हस्तक्षेप के लिए कठिन धन्यवाद है।एक नया कॉल स्टैक आवंटित करना

मेरे पास एक खिलौना कंपाइलर है जो मैं एक स्क्रिप्टिंग भाषा के लिए काम कर रहा हूं। प्रगति पर होने पर एक स्क्रिप्ट के निष्पादन को रोकने में सक्षम होने के लिए और मेजबान प्रोग्राम पर लौटने में सक्षम होने के लिए, इसका अपना ढेर है: "स्टैक पॉइंटर" वैरिएबल के साथ मेमोरी का एक साधारण ब्लॉक जो सामान्य सी कोड संचालन का उपयोग करके वृद्धि करता है उस तरह की चीज के लिए और इतने पर और आगे। अभी तक दिलचस्प नहीं है।

फिलहाल मैं सी को संकलित करता हूं लेकिन मुझे मशीन कोड के साथ संकलन की जांच करने में दिलचस्पी है - जबकि द्वितीयक ढेर और पूर्वनिर्धारित नियंत्रण बिंदुओं पर मेजबान कार्यक्रम में लौटने की क्षमता रखते हुए।

तो ... मुझे लगता है कि मेरे अपने कोड के भीतर पारंपरिक स्टैक रजिस्टरों का उपयोग करने में कोई समस्या नहीं होने की संभावना है, मुझे लगता है कि रजिस्टरों के साथ क्या होता है, जब तक यह पूरा हो जाता है तब तक सबकुछ बहाल हो जाता है अगर मैं इस बिंदु पर गलत हूं तो मुझे सही करें)। लेकिन ... यदि मैं स्क्रिप्ट कोड को किसी अन्य लाइब्रेरी कोड पर कॉल करना चाहता हूं, तो यह "वर्चुअल स्टैक" का उपयोग करके प्रोग्राम छोड़ना सुरक्षित है, या यह आवश्यक है कि इसे इस उद्देश्य के लिए मूल स्टैक दिया जाए ?

this one और this one जैसे उत्तर बताते हैं कि स्टैक स्मृति का पारंपरिक ब्लॉक नहीं है, लेकिन यह पृष्ठ दोषों और क्या नहीं के साथ विशेष, सिस्टम विशिष्ट व्यवहार पर निर्भर करता है।

तो:

  • इसे सुरक्षित स्मृति के कुछ अन्य क्षेत्र में ढेर संकेत ले जाने के लिए है? ढेर स्मृति "विशेष" नहीं है? मुझे लगता है कि थ्रेडिंग लाइब्रेरीज़ को ऐसा कुछ करना होगा, क्योंकि वे अधिक स्टैक बनाते हैं ...
  • मानते हैं कि मेमोरी का कोई भी क्षेत्र स्टैक रजिस्टरों और निर्देशों का उपयोग करके हेरफेर करने के लिए सुरक्षित है, मुझे कोई कारण नहीं है कि यह एक समस्या क्यों होगी एक ज्ञात कॉल गहराई (यानी कोई रिकर्सन, कोई फ़ंक्शन पॉइंटर्स) के साथ किसी भी फ़ंक्शन को कॉल करें जब तक वह वर्चुअल स्टैक पर उपलब्ध न हो। सही?
  • स्टैक ओवरफ़्लो स्पष्ट रूप से सामान्य कोड में एक समस्या है, लेकिन क्या इस तरह के सिस्टम में ओवरफ़्लो के लिए कोई अतिरिक्त विनाशकारी परिणाम होगा?

यह स्पष्ट रूप से वास्तव में आवश्यक नहीं है, के बाद से बस असली ढेर की ओर इशारा लौटने पूरी तरह से उपयोगी हो जाएगा, या उस बात के लिए उन्हें पहली जगह में कोस नहीं और सिर्फ कम रजिस्टरों के साथ डाल, और मैं शायद shouldn इसे बिल्कुल करने की कोशिश नहीं करें (कम से कम मेरी गहराई से बाहर होने के कारण)। लेकिन मैं अभी भी उत्सुक हूँ। जानना चाहते हैं कि इस तरह की चीजें कैसे काम करती हैं।

संपादित करें: क्षमा करें, कहना चाहिए था। मैं x86 (32-बिट अपनी मशीन के लिए), विंडोज और उबंटू पर काम कर रहा हूं। कुछ भी विदेशी नहीं है।

+1

इन सवालों के जवाब अत्यधिक मंच-विशिष्ट होंगे। कृपया बताएं कि आप किस प्लेटफ़ॉर्म पर काम कर रहे हैं। –

+0

क्या आप अधिक विशिष्ट हो सकते हैं जो आप करना चाहते हैं? हो सकता है कि आप अपने वर्चुअल स्टैक पॉइंटर द्वारा क्या मतलब रखते हैं और आप होस्ट प्रक्रिया में नियंत्रण कैसे वापस लेना चाहते हैं इसका एक उदाहरण प्रदान करते हैं? –

+0

वर्चुअल स्टैक पॉइंटर केवल एक नियमित सी चर है जो कहीं भी स्मृति ब्लॉक में इंगित करता है। "मेजबान कार्यक्रम पर लौटने" का शाब्दिक अर्थ है स्क्रिप्ट फ़ंक्शन से वापस लौटना (इसलिए यदि हम रजिस्टरों के साथ गड़बड़ कर रहे हैं, तो इसका मतलब यह होगा कि उन्हें वापस लौटने से पहले उन्हें वापस सेट करना होगा)। अनिवार्य रूप से वही चीजें जो आपके पास दुभाषिया में होंगी; दुभाषिया वस्तु अपना स्वयं का अलग कार्यक्रम राज्य बनाए रखती है। – Leushenko

उत्तर

4

ये सभी उत्तर "सामान्य प्रोसेसर आर्किटेक्चर" पर आधारित हैं, और चूंकि इसमें असेंबलर कोड उत्पन्न करना शामिल है, इसलिए इसे "लक्ष्य विशिष्ट" होना चाहिए - यदि आप प्रोसेसर एक्स पर ऐसा करने का निर्णय लेते हैं, जिसमें कुछ अजीब हैंडलिंग है ढेर, नीचे स्पष्ट रूप से स्क्रीनसेफ के लायक नहीं है [पेपर के विकल्प] पर लिखा गया है। X86 सामान्य रूप से, नीचे दिए गए हैं जब तक कि अन्यथा न कहा गया हो।

is it safe to move the stack pointers into some other area of memory? 

ढेर स्मृति "विशेष" नहीं है?के रूप में इस तरह के विशेष नहीं है मैं पुस्तकालयों सूत्रण, स्मृति कुछ इस तरह करना चाहिए के रूप में वे अधिक ढेर बनाने ...

आंकड़ा। हालांकि यह मानता है कि यह x86 आर्किटेक्चर पर नहीं है जहां स्टैक सेगमेंट को स्टैक उपयोग को सीमित करने के लिए उपयोग किया जाता है। हालांकि यह संभव है, कार्यान्वयन में देखना दुर्लभ है। मुझे पता है कि कुछ साल पहले नोकिया के पास 32-बिट मोड में सेगमेंट का उपयोग करके एक विशेष ऑपरेटिंग सिस्टम था। जहां तक ​​मैं अभी इस बारे में सोच सकता हूं, वही एकमात्र ऐसा है जिसके साथ मुझे कोई संपर्क मिला है, जो x86-विभाजन मोड के वर्णन के लिए स्टैक सेगमेंट का उपयोग करता है।

स्मृति के किसी भी क्षेत्र मानते हुए, ढेर रजिस्टर और निर्देशों का उपयोग कर हेरफेर करने के लिए सुरक्षित है मुझे कोई कारण नहीं के बारे में सोच क्यों यह एक समस्या (यानी कोई प्रत्यावर्तन एक ज्ञात कॉल गहराई के साथ किसी भी कार्यों कॉल करने के लिए किया जाएगा कर सकते हैं , कोई फंक्शन पॉइंटर्स नहीं) जब तक वह वर्चुअल स्टैक पर उपलब्ध है। सही?

सही। बस जब तक आप मूल स्टैक पर वापस स्विच किए बिना किसी अन्य फ़ंक्शन पर वापस जाने में सक्षम होने की अपेक्षा नहीं करते हैं। रिकर्सन का सीमित स्तर भी स्वीकार्य होगा, जब तक ढेर पर्याप्त गहरा होता है [कुछ प्रकार की समस्याएं होती हैं जो बिना रिकर्सन के हल करने के लिए निश्चित रूप से कठिन होती हैं - उदाहरण के लिए बाइनरी पेड़ खोज]।

ढेर अतिप्रवाह स्पष्ट रूप से सामान्य कोड में एक समस्या वैसे भी है, लेकिन वहाँ में एक अतिप्रवाह के लिए किसी भी अतिरिक्त विनाशकारी परिणाम एक ऐसी प्रणाली हो सकता है?

दरअसल, यदि आप थोड़ा दुर्भाग्यपूर्ण हैं तो क्रैक करना कठिन होगा।

मैं सुझाव है कि आप के रूप में अपठनीय और unwriteable "ढेर के अंत" चिह्नित करने के लिए इतना है कि यदि आपका कोड गलती से ढेर बंद चलता है, यह ठीक से दुर्घटनाओं VirtualProtect() (Windows) या mprotect() (लिनक्स आदि) के लिए एक कॉल का उपयोग कुछ अन्य सूक्ष्म अपरिभाषित व्यवहार की बजाय [क्योंकि यह गारंटी नहीं है कि नीचे दी गई स्मृति (निचला पता) अनुपलब्ध है, इसलिए यदि आप स्टैक से बाहर निकलते हैं तो आप कुछ अन्य उपयोगी चीजों को ओवरराइट कर सकते हैं, और इससे कुछ डीबग करना मुश्किल हो जाएगा कीड़े]।

कुछ कोड जोड़ना जो मौलिक रूप से स्टैक गहराई की जांच करता है (आपको पता है कि आपका स्टैक कहां शुरू होता है और समाप्त होता है, इसलिए यह जांचना मुश्किल नहीं होना चाहिए कि कोई विशेष स्टैक मान "सीमा के बाहर" है [यदि आप स्वयं को देते हैं ढेर के शीर्ष के बीच कुछ "अतिरिक्त बफर स्पेस" और "हम मर चुके हैं" जोन आपने संरक्षित किया - एक "क्रंबल जोन" क्योंकि वे इसे कॉल करेंगे अगर यह एक दुर्घटना में कार थी]। आप भी भर सकते हैं एक पहचानने योग्य पैटर्न के साथ पूरा ढेर, और जांचें कि इसमें से कितना "छेड़छाड़" है।

+0

किसी भी रिकर्सिव एल्गोरिदम को एक बहुत ही समान पुनरावर्तक में परिवर्तित किया जा सकता है (आमतौर पर काफी दर्द रहित) जो एक हीप-आवंटित स्टैक संरचना (डेटा-संरचना अर्थ में "ढेर") का उपयोग करता है। –

+0

हां, सहमत हुए। लेकिन जब यह एक तकनीकी परिप्रेक्ष्य से अपेक्षाकृत आसान है, यह जटिलता की एक परत को कुछ कोड में जोड़ता है जो वास्तविक सरल शुरू होता है। एक (अच्छी तरह से संतुलित) बाइनरी पेड़ 20 रिकर्सन स्तरों में 1 एम प्रविष्टियों के माध्यम से खोज सकता है - मानते हैं कि प्रत्येक रिकर्सन स्तर के लिए संग्रहीत डेटा बहुत बड़ा नहीं है, यह निश्चित रूप से एक काफी छोटे ढेर की सीमाओं के भीतर है। –

+0

उत्तर अच्छा लगता है, धन्यवाद! जहां तक ​​रिकर्सन जाता है, मैं दूसरी ढेर को काफी बड़ा बनाने की योजना बना रहा था, इसलिए विशेष रूप से छोटी बाध्य रिकर्सिव स्थितियों के बारे में चिंता नहीं कर रहा था। – Leushenko

2

आमतौर पर, 86 पर, आप मौजूदा ढेर बिना किसी समस्या के उपयोग कर सकते हैं जब तक कि:

  • आप अतिप्रवाह नहीं है यह
  • आप pop या साथ ढेर सूचक रजिस्टर (नहीं बढ़ाते add esp, positive_value/sub esp, negative_value) आपके कोड के साथ शुरू होने से परे (यदि आप करते हैं, इंटरप्ट या असीमित कॉलबैक (सिग्नल) या स्टैक का उपयोग कर कोई अन्य गतिविधि इसकी सामग्री को मिटाएगी)
  • आप कोई CPU अपवाद नहीं करते हैं (यदि आप करते हैं, अपवाद हैंडलिंग कोड स्टैक टी को खोलने में सक्षम नहीं हो सकता है ओ निकटतम बिंदु है जहां अपवाद संभाला जा सकता है)

ही एक अस्थायी ढेर के लिए स्मृति का एक अलग ब्लॉक का उपयोग और उसके अंत करने के लिए esp ओर इशारा करते हुए लागू होता है।

अपवाद हैंडलिंग और स्टैक के साथ समस्या यह आपके संकलित कि C और C++ कोड कुछ अपवाद-हैंडलिंग से संबंधित उनके संबंधित अपवाद संचालकों के लिंक के साथ eip की सीमाओं की तरह डेटा संरचना में शामिल है इस तथ्य से कोई लेना देना नहीं है (यह बताता है जहां निकटतम अपवाद हैंडलर कोड के प्रत्येक टुकड़े के लिए है) और कॉलिंग फ़ंक्शन की पहचान से संबंधित कुछ जानकारी भी है (यानी जहां रिटर्न पता स्टैक पर है, आदि) ताकि आप अपवादों को बुलबुला कर सकें। यदि आप इस "ढांचे" में कच्चे मशीन कोड को प्लग करते हैं, तो आप इसे कवर करने के लिए इन अपवाद-हैंडलिंग डेटा संरचनाओं को उचित रूप से विस्तारित नहीं करेंगे, और यदि चीजें गलत हो जाती हैं, तो वे शायद बहुत गलत हो जाएंगे (पूरी प्रक्रिया क्रैश हो सकती है या जेनरेट कोड के आस-पास अपवाद हैंडलर होने के बावजूद क्षतिग्रस्त हो जाएं)।

तो, हाँ, अगर आप सावधान हैं, तो आप ढेर के साथ खेल सकते हैं।

2

आप प्रोसेसर के ढेर के लिए किसी भी क्षेत्र का उपयोग कर सकते हैं (स्मृति सुरक्षा मॉड्यूल)।

अनिवार्य रूप से, आप बस नए क्षेत्र में एक सूचक के साथ ईएसपी रजिस्टर ("MOV ESP, ...") लोड करते हैं, हालांकि आप इसे आवंटित करने में कामयाब रहे।

आपके पास आपके प्रोग्राम के लिए पर्याप्त है, और जो भी इसे कॉल कर सकता है (उदा।, एक विंडोज ओएस एपीआई), और ओएस के जो भी मजाकिया व्यवहार है। आप यह पता लगाने में सक्षम हो सकते हैं कि आपके कोड की कितनी जगह चाहिए; एक अच्छा संकलक आसानी से ऐसा कर सकता है। यह पता लगाना कि विंडोज़ द्वारा कितना जरूरी है; आप हमेशा "बहुत अधिक रास्ता" आवंटित कर सकते हैं जो विंडोज प्रोग्राम करता है।

यदि आप इस स्थान को कसकर प्रबंधित करने का निर्णय लेते हैं, तो आपको शायद विंडोज फ़ंक्शंस को कॉल करने के लिए स्टैक स्विच करना होगा। वह पर्याप्त नहीं होगा; आप विभिन्न विंडोज आश्चर्यों से जला दिया जाएगा। मैं उनमें से एक का वर्णन करता हूं Windows: avoid pushing full x86 context on stack। मेरे पास मध्यम समाधान हैं, लेकिन इसके लिए अच्छे समाधान नहीं हैं।

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