2011-12-01 8 views
11

वास्तव में विचित्र gcc quirk। के बाद से अपने एक 100 * 4 सरणीजीसीसी किसी बड़े फंक्शन कॉल के साथ बड़ी सरणी आवंटित करते समय स्टैक पॉइंटर को गलत मान क्यों घटाता है?

0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 48 81 ec 18 01 00 00 sub $0x118,%rsp 
    b: c7 85 70 fe ff ff 01 movl $0x1,-0x190(%rbp) 
    12: 00 00 00 
    15: c9      leaveq 
    16: c3      retq 

ढेर के शीर्ष स्पष्ट रूप से 400,: इस की जाँच करें:

main() { int a[100]; a[0]=1; } 

इस विधानसभा पैदा करता है। तो जब यह पहली प्रविष्टि को लिखता है, तो यह आरबीपी - 400 (लाइन 'बी') करता है। अच्छा। लेकिन यह स्टैक (लाइन '4') सूचक से 280 घटाता है? क्या यह सरणी के बीच में इंगित नहीं करता है?

हम बाद में एक समारोह कॉल जोड़ते हैं, जीसीसी सही काम करता है:

b() {} 
main() { int a[100]; a[0]=1; b(); } 

इस विधानसभा का उत्पादन:, यह ठीक से घटा 400

0000000000000000 <b>: 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: c9      leaveq 
    5: c3      retq 

0000000000000006 <main>: 
    6: 55      push %rbp 
    7: 48 89 e5    mov %rsp,%rbp 
    a: 48 81 ec 90 01 00 00 sub $0x190,%rsp 
    11: c7 85 70 fe ff ff 01 movl $0x1,-0x190(%rbp) 
    18: 00 00 00 
    1b: b8 00 00 00 00   mov $0x0,%eax 
    20: e8 00 00 00 00   callq 25 <main+0x1f> 
    25: c9      leaveq 
    26: c3      retq 

यहाँ (लाइन 'एक')।

जब आप फ़ंक्शन कॉल जोड़ते हैं तो परिवर्तन क्यों होता है? क्या जीसीसी सिर्फ आलसी है, और यह सही नहीं करता है क्योंकि इससे कोई फर्क नहीं पड़ता? क्या हो रहा है? जाहिर है यह केवल तब होता है जब x86_64 के लिए संकलन होता है, लेकिन सादा x86 के लिए नहीं। क्या x86_64 के "रेडज़ोन" के साथ ऐसा कुछ अजीब है? क्या हो रहा है ठीक है?

+0

आप कोड के बारे में चिंतित क्यों हैं जिसका कोई प्रभाव नहीं है, जैसा कि कोड से स्पष्ट है !? साथ ही, आपके (दूसरे) उदाहरण को कुछ कॉलिंग सम्मेलन का उपयोग करना चाहिए जहां स्टैक शामिल है, क्योंकि आपके उदाहरण में कोई पैरामीटर शामिल नहीं है (स्टैक पर)। साइड-नोट: मुझे एटी एंड टी असेंबली से नफरत है :) – 0xC0000022L

+3

शायद जिज्ञासा के कारण? या यह आपकी पुस्तक में वैध कारण नहीं है? बीटीडब्लू, मुझे – hirschhornsalz

उत्तर

13

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

लाल क्षेत्र केवल 64 बिट लिनक्स, BSD और मैक में इस्तेमाल किया जा सकता है। यह कर्नेल कोड में उपलब्ध नहीं है।

यह अंतरिक्ष के लिए अनुकूलन करने के लिए लाल क्षेत्र के साथ जब से तुम कम निर्देश के साथ स्थानीय चर की 512 बाइट्स, केवल आरएसपी और ईबीपी के आधार पर करने के लिए संदर्भित कर सकते हैं इस्तेमाल किया जा सकता है। लाल क्षेत्र के बिना केवल 384 बाइट उपलब्ध हैं। इस सीमा के बाहर के सभी स्थानीय चर लंबे कोड या अतिरिक्त रजिस्टरों के साथ उपयोग किए जाते हैं।

अपने उदाहरण के लिए, लाल क्षेत्र का उपयोग कर आवश्यक नहीं है, लेकिन जीसीसी सभी "पत्ता" कार्यों के लिए इसका इस्तेमाल करते हैं पसंद करती हैं। इस तरह संकलक को कार्यान्वित करना आसान है।

+0

ज्ञान का ज्ञान मिला, लाल क्षेत्र के बारे में कर्नेल कोड में उपलब्ध नहीं है: असल में, लिनक्स कर्नेल इसका सम्मान नहीं करता है। –

5

x86-64 एबीआई स्टैक पॉइंटर से परे 128 बाइट्स के 'लाल क्षेत्र' को अनिवार्य करता है जिसका उपयोग %rsp को संशोधित किए बिना किया जा सकता है। पहले उदाहरण में, main() एक पत्ता समारोह है, इसलिए संकलक स्टैक स्पेस के उपयोग को अनुकूलित कर रहा है - यानी, कोई फ़ंक्शन कॉल नहीं है, इसलिए इस क्षेत्र को ओवरराइट नहीं किया जाएगा।

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