अधिकांश आधुनिक प्रणालियों में स्टैक वृद्धि की दिशा क्या है?


102

मैं सी में कुछ प्रशिक्षण सामग्री तैयार कर रहा हूं और मैं चाहता हूं कि मेरे उदाहरण ठेठ स्टैक मॉडल को फिट करने के लिए हैं।

लिनक्स, विंडोज, मैक ओएसएक्स (पीपीसी और x86), सोलारिस और सबसे हाल ही में यूनिक्स में सी स्टैक किस दिशा में बढ़ता है?


3
क्यों नीचे की ओर संस्करण: stackoverflow.com/questions/2035568/…
Ciro Santilli 病:::

जवाबों:


147

स्टैक वृद्धि आमतौर पर ऑपरेटिंग सिस्टम पर ही निर्भर नहीं करती है, लेकिन प्रोसेसर पर यह चल रही है। उदाहरण के लिए सोलारिस, x86 और SPARC पर चलता है। Mac OSX (जैसा कि आपने बताया) PPC और x86 पर चलता है। लिनक्स मेरे बड़े होनकिन 'सिस्टम z' की हर चीज पर काम करता है जो एक छोटी छोटी कलाई घड़ी पर काम करता है ।

यदि सीपीयू किसी भी तरह का विकल्प प्रदान करता है, तो ओएस द्वारा उपयोग किया जाने वाला एबीआई / कॉलिंग कन्वेंशन निर्दिष्ट करता है कि आपको कौन सा विकल्प चाहिए अगर आप चाहते हैं कि आपका कोड हर किसी के कोड को कॉल करे।

प्रोसेसर और उनकी दिशा हैं:

  • x86: नीचे।
  • स्पार्क: चयन करने योग्य। मानक ABI उपयोग करता है।
  • पीपीसी: नीचे, मुझे लगता है।
  • सिस्टम z: एक लिंक की गई सूची में, मैं आपको बच्चा नहीं (लेकिन अभी भी नीचे, कम से कम zLinux के लिए)।
  • एआरएम: चयन करने योग्य है, लेकिन थम्ब 2 में केवल नीचे के लिए कॉम्पैक्ट एन्कोडिंग हैं (एलडीएमआईए = वृद्धि के बाद, एसटीएमडीबी = इससे पहले की गिरावट)।
  • 6502: डाउन (लेकिन केवल 256 बाइट्स)।
  • आरसीए 1802 ए: किसी भी तरह से आप चाहते हैं, एससीआरटी कार्यान्वयन के अधीन है।
  • PDP11: नीचे।
  • 8051: अप।

उन आखिरी कुछ पर मेरी उम्र दिखाते हुए, 1802 चिप था जिसका उपयोग शुरुआती शटर को नियंत्रित करने के लिए किया जाता था (अगर दरवाजे खुले थे, तो मुझे संदेह था, मुझे शक है कि प्रसंस्करण शक्ति के आधार पर :-) और मेरा दूसरा कंप्यूटर, COMX-35 ( मेरे ZX80 के बाद )।

PDP11 से बटोरा विवरण यहाँ से, 8051 विवरण यहाँ

SPARC आर्किटेक्चर एक स्लाइडिंग विंडो रजिस्टर मॉडल का उपयोग करता है। वास्तुकला में दिखाई देने वाले विवरणों में रजिस्टर-खिड़कियों का एक परिपत्र बफर भी शामिल है, जो आंतरिक रूप से वैध और कैश्ड हैं, जब जाल उस से अधिक / कम होते हैं। देखें यहाँ जानकारी के लिए। जैसा कि SPARCv8 मैनुअल बताता है , SAVE और बाकी निर्देश ADD निर्देश और रजिस्टर-विंडो रोटेशन की तरह हैं। सामान्य ऋणात्मक के बजाय सकारात्मक स्थिरांक का उपयोग करने से उर्ध्वगामी वृद्धि होती है।

उपर्युक्त SCRT तकनीक एक और है - 1802 में कुछ का उपयोग किया गया या यह SCRT के लिए सोलह 16-बिट रजिस्टर (मानक कॉल और वापसी तकनीक) है। एक प्रोग्राम काउंटर था, आप SEP Rnनिर्देश के साथ पीसी के रूप में किसी भी रजिस्टर का उपयोग कर सकते हैं । एक स्टैक पॉइंटर था और दो को हमेशा एससीआरटी कोड एड्रेस, कॉल के लिए एक, रिटर्न के लिए एक को इंगित करने के लिए सेट किया गया था। किसी भी रजिस्टर को एक विशेष तरीके से व्यवहार नहीं किया गया था। ध्यान रखें कि ये विवरण स्मृति से हैं, वे पूरी तरह से सही नहीं हो सकते हैं।

उदाहरण के लिए, यदि R3 पीसी था, R4 SCRT कॉल एड्रेस था, R5 SCRT रिटर्न एड्रेस था और R2 "स्टैक" था (सॉफ्टवेयर में इसे लागू किया गया है तो उद्धरण), SEP R4R4 को PC के रूप में सेट करेगा और SCRT को चलाना शुरू करेगा। कॉल कोड।

इसके बाद यह R2 "ढेर" (मुझे लगता है कि R6 अस्थायी भंडारण के लिए इस्तेमाल किया गया था) पर R3 संग्रहीत करेंगे इसे एडजस्ट करने या नीचे, R3 निम्नलिखित दो बाइट्स हड़पने, उन्हें लोड में R3, तो SEP R3और नए पते पर चल रहा हो।

वापस लौटने के लिए, यह SEP R5आर 2 स्टैक से पुराने पते को खींच लेगा, इसमें दो जोड़ देगा (कॉल के पते बाइट्स को छोड़ने के लिए), इसे R3 में लोड करें और SEP R3पिछले कोड को चलाना शुरू करें।

सभी 6502/6809 / z80 स्टैक-आधारित कोड के बाद शुरू में अपने सिर को चारों ओर लपेटने के लिए बहुत कठिन है, लेकिन फिर भी एक बैंग-योर-हेड-विरुद्ध-द-दीवार तरह से सुरुचिपूर्ण है। इसके अलावा चिप की बड़ी बिक्री वाली विशेषताओं में से एक 16 16-बिट रजिस्टरों का एक पूर्ण सूट था, इस तथ्य के बावजूद कि आपने तुरंत उनमें से 7 (एससीआरटी के लिए 5, डीएमए के लिए दो और स्मृति से बाधित)। अह, वास्तविकता पर विपणन की विजय :-)

सिस्टम z वास्तव में काफी समान है, कॉल / रिटर्न के लिए अपने R14 और R15 रजिस्टरों का उपयोग करता है।


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

1
एआरएम दुनिया के छोटे से हिस्से में मैंने अब तक (ARM7TDMI) देखा है कि स्टैक पूरी तरह से सॉफ्टवेयर में संभाला जाता है। रिटर्न पते को एक रजिस्टर में संग्रहीत किया जाता है, जो यदि आवश्यक हो तो सॉफ्टवेयर द्वारा सहेजा जाता है, और पूर्व / बाद के वेतन वृद्धि / गिरावट के निर्देश इसे और अन्य सामान को किसी भी दिशा में स्टैक पर रखने की अनुमति देते हैं।
स्टारब्लू

1
एक HPPA, ढेर हो गया! यथोचित आधुनिक आर्किटेक्चर के बीच बहुत कम।
tml

2
जिज्ञासु के लिए, यहाँ एक अच्छा संसाधन है कि कैसे z / OS पर स्टैक काम करता है: www-03.ibm.com/systems/resources/Stack+and+Heap.pdf
डिलन कोवेर

1
आपकी समझ के लिए धन्यवाद @paxdiablo। जब आप इस तरह की टिप्पणी करते हैं, तो कभी-कभी लोग इसे एक व्यक्तिगत संबंध के रूप में लेते हैं, खासकर जब यह एक पुराना होता है। मुझे केवल इतना पता है कि एक अंतर है क्योंकि मैंने अतीत में खुद से वही गलती की है। ख्याल रखना।
कासाडेबरसन

23

C ++ में (C के अनुकूल) stack.cc :

static int
find_stack_direction ()
{
    static char *addr = 0;
    auto char dummy;
    if (addr == 0)
    {
        addr = &dummy;
        return find_stack_direction ();
    }
    else
    {
        return ((&dummy > addr) ? 1 : -1);
    }
}

14
वाह, बहुत समय हो गया है जब मैंने "ऑटो" कीवर्ड देखा है।
पैक्सिडाब्लो

9
(और डमी> एड्र) अपरिभाषित है। किसी रिलेशनल ऑपरेटर को दो पॉइंटर्स खिलाने का नतीजा केवल तभी परिभाषित किया जाता है जब दो पॉइंटर्स एक ही ऐरे या स्ट्रक्चर के भीतर पॉइंट होते हैं।
सिगाजाइस

2
अपने स्वयं के स्टैक के लेआउट की जांच करने की कोशिश करना - ऐसा कुछ जिसे C / C ++ बिल्कुल निर्दिष्ट नहीं करता है - के साथ शुरू करने के लिए "महत्वहीन" है, इसलिए मैं वास्तव में उस पर ध्यान नहीं दूंगा। ऐसा लगता है कि यह फ़ंक्शन केवल एक बार सही ढंग से काम करेगा, हालांकि।
14

9
इसके लिए उपयोग करने की कोई आवश्यकता नहीं है static। इसके बजाय आप एक पुनरावर्ती कॉल के लिए एक तर्क के रूप में पते को पास कर सकते हैं।
आर .. गिटहब स्टॉप हेल्पिंग ICE

5
इसके अलावा, एक का उपयोग करके static, यदि आप इसे एक से अधिक बार कॉल करते हैं, तो बाद की कॉल विफल हो सकती हैं ...
क्रिस डोड

7

नीचे बढ़ने का लाभ पुराने सिस्टम में है स्टैक आमतौर पर मेमोरी के शीर्ष पर था। कार्यक्रम आम तौर पर नीचे से शुरू होने वाली मेमोरी को भर देते हैं। इस प्रकार के मेमोरी मैनेजमेंट ने स्टैक के निचले हिस्से को कहीं न कहीं समझदारी से मापने और जगह देने की आवश्यकता को कम कर दिया है।


3
'लाभ' नहीं, वास्तव में एक तनातनी।
Lorne

1
तनावरहित नहीं। बिंदु यह है कि दो बढ़ते हुए स्मृति क्षेत्रों में हस्तक्षेप नहीं किया जा रहा है (जब तक कि स्मृति पूरी तरह से नहीं है), जैसा कि @valenok ने बताया।
यव्सगेरेवाई

6

स्टैक x86 पर बढ़ता है (आर्किटेक्चर द्वारा परिभाषित, पॉप इंक्रीमेंट स्टैक पॉइंटर, पुश डिक्रीमेंट।)


5

MIPS और कई आधुनिक RISC आर्किटेक्चर (जैसे PowerPC, RISC-V, SPARC ...) में कोई निर्देश pushऔर popनिर्देश नहीं हैं । उन कार्यों को स्पष्ट रूप से स्टैक पॉइंटर को मैन्युअल रूप से समायोजित करने के द्वारा किया जाता है फिर मूल्य को समायोजित पॉइंटर के लिए अपेक्षाकृत अधिक लोड / स्टोर करता है। सभी रजिस्टर (शून्य रजिस्टर को छोड़कर) सामान्य उद्देश्य हैं, इसलिए सिद्धांत रूप में कोई भी रजिस्टर एक स्टैक पॉइंटर हो सकता है, और स्टैक किसी भी दिशा में बढ़ सकता है जो प्रोग्रामर चाहता है

कहा कि, स्टैक आमतौर पर अधिकांश आर्किटेक्चर पर बढ़ता है, संभवतः मामले से बचने के लिए जब स्टैक और प्रोग्राम डेटा या हीप डेटा बढ़ता है और एक दूसरे से टकराता है। वहाँ भी महान पता कारण श-'s जवाब का उल्लेख किया है । कुछ उदाहरण: MIPS ABI नीचे की ओर बढ़ता है और स्टैक पॉइंटर के रूप में $29(AKA $sp) का उपयोग करता है, RISC-V ABI भी नीचे की तरफ बढ़ता है और स्टैक पॉइंटर के रूप में x2 का उपयोग करता है

इंटेल 8051 में स्टैक बड़ा हो जाता है, शायद इसलिए कि मेमोरी स्पेस इतना छोटा है (मूल संस्करण में 128 बाइट्स) जिसमें कोई ढेर नहीं है और आपको स्टैक को शीर्ष पर रखने की आवश्यकता नहीं है ताकि यह ढेर से अलग हो जाए नीचे से

आप https://en.wikipedia.org/wiki/Calling_conference में विभिन्न आर्किटेक्चर में स्टैक उपयोग के बारे में अधिक जानकारी प्राप्त कर सकते हैं

यह सभी देखें


2

अन्य उत्तरों के लिए एक छोटा सा जोड़, जो कि जहाँ तक मैं देख सकता हूँ, इस बिंदु को नहीं छुआ है:

स्टैक को नीचे की ओर बढ़ने से स्टैक के भीतर सभी पते स्टैक पॉइंटर के सापेक्ष एक सकारात्मक ऑफसेट होते हैं। नकारात्मक ऑफसेट की कोई आवश्यकता नहीं है, क्योंकि वे केवल अप्रयुक्त स्टैक स्थान की ओर इशारा करेंगे। जब प्रोसेसर स्टैकपॉइंट-रिलेटिव एड्रेसिंग को सपोर्ट करता है तो यह स्टैकिंग लोकेशन को सरल बनाता है।

कई प्रोसेसर के निर्देश हैं जो कुछ रजिस्टर के सापेक्ष केवल सकारात्मक ऑफसेट के साथ एक्सेस की अनुमति देते हैं। इनमें कई आधुनिक आर्किटेक्चर शामिल हैं, साथ ही कुछ पुराने भी हैं। उदाहरण के लिए, एआरएम थम्ब एबीआई 16 सिंगल-बिट निर्देश शब्द के भीतर एन्कोडेड पॉजिटिव ऑफसेट के साथ स्टैकपॉइंट-रिलेटिव एक्सेस के लिए प्रदान करता है।

यदि स्टैक ऊपर की ओर बढ़ता है, तो स्टैकपॉइंट के सापेक्ष सभी उपयोगी ऑफसेट नकारात्मक होंगे, जो कम सहज और कम सुविधाजनक है। यह रजिस्टर-सापेक्ष पते के अन्य अनुप्रयोगों के साथ भी है, उदाहरण के लिए एक संरचना के क्षेत्रों तक पहुँचने के लिए।


2

अधिकांश प्रणालियों पर, स्टैक नीचे बढ़ता है, और https://gist.github.com/cpq/8598782 पर मेरा लेख बताता है कि यह क्यों बढ़ता है। यह सरल है: मेमोरी के एक निश्चित भाग में दो बढ़ते हुए मेमोरी ब्लॉक (ढेर और स्टैक) को कैसे लेआउट करें? सबसे अच्छा उपाय यह है कि उन्हें विपरीत छोर पर रखा जाए और एक-दूसरे की तरफ बढ़ने दिया जाए।


कि सार अब मर चुका हो रहा है :(
Ven

@ वी - मैं इसे प्राप्त कर सकता हूं
ब्रेट होलमैन

1

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


0

इस मैक्रो को यूबी के बिना रनटाइम पर इसका पता लगाना चाहिए:

#define stk_grows_up_eh() stk_grows_up__(&(char){0})
_Bool stk_grows_up__(char *ParentsLocal);

__attribute((__noinline__))
_Bool stk_grows_up__(char *ParentsLocal) { 
    return (uintptr_t)ParentsLocal < (uintptr_t)&ParentsLocal;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.