2009-06-30 17 views
40

मैं कंपाइलर्स मशीन कोड कैसे उत्पन्न करता है, और अधिक विशेष रूप से जीसीसी स्टैक के साथ कैसे व्यवहार करता है, इसकी गहरी समझ हासिल करने का प्रयास कर रहा हूं। ऐसा करने में मैं सरल सी प्रोग्राम लिख रहा हूं, उन्हें असेंबली में संकलित कर रहा हूं और परिणाम को समझने के लिए अपनी पूरी कोशिश कर रहा हूं। यहाँ एक सरल कार्यक्रम है और आउटपुट उत्पन्न:स्टैक आवंटन, पैडिंग और संरेखण

asmtest.c:

void main() { 
    char buffer[5]; 
} 

asmtest.s:

pushl %ebp 
movl %esp, %ebp 
subl $24, %esp 
leave 
ret 

क्या मुझे puzzling है यही कारण है कि 24 बाइट्स ढेर के लिए आवंटित किया जा रहा है। मुझे पता है कि कैसे प्रोसेसर स्मृति को संबोधित करता है, स्टैक को 4 की वृद्धि में आवंटित किया जाना चाहिए, लेकिन यदि यह मामला था, तो हमें केवल स्टैक पॉइंटर को 8 बाइट्स तक ले जाना चाहिए, 24 नहीं। संदर्भ के लिए, 17 का बफर बाइट्स एक स्टैक पॉइंटर 40 बाइट्स ले जाते हैं और स्टैक पॉइंटर 8 की सभी चालों पर कोई बफर नहीं होता है। 1 और 16 बाइट्स के बीच एक बफर समावेशी चाल ESP 24 बाइट्स।

अब मानते हुए कि 8 बाइट एक आवश्यक स्थिर है (इसके लिए क्या आवश्यक है?), इसका मतलब है कि हम 16 बाइट्स के टुकड़ों में आवंटित कर रहे हैं। संकलक इस तरह से संरेखित क्यों होगा? मैं एक x86_64 प्रोसेसर का उपयोग कर रहा हूं, लेकिन 64 बिट शब्द को केवल 8 बाइट संरेखण की आवश्यकता होनी चाहिए। विसंगति क्यों?

संदर्भ के लिए मैं इसे मैक 4.0.1 के साथ चल रहे मैक पर संकलित कर रहा हूं और कोई ऑप्टिमाइज़ेशन सक्षम नहीं है।

उत्तर

43

यह एक जीसीसी सुविधा -mpreferred-stack-boundary=n द्वारा नियंत्रित है जहां संकलक 2^n पर गठित स्टैक पर आइटम रखने की कोशिश करता है। यदि आपने n को 2 में बदल दिया है, तो यह केवल स्टैक पर 8 बाइट आवंटित करेगा। n के लिए डिफ़ॉल्ट मान 4 है यानी यह 16-बाइट सीमाओं को संरेखित करने का प्रयास करेगा।

क्यों "डिफ़ॉल्ट" 8 बाइट्स और उसके बाद 24 = 8 + 16 बाइट्स है क्योंकि ढेर पहले से ही leave और ret के लिए 8 बाइट का है है, इसलिए संकलित कोड मिलता है इसे करने के लिए गठबंधन करने के लिए 8 बाइट्स से पहले ढेर समायोजित करना चाहिए 2^4 = 16।

+0

ने "बाइट% ebp" बनाया था एएसपी 8 बाइट से कम किया? प्लस रेट 8 बाइट्स, पहले से ही 16-बाइट के साथ गठबंधन किया जाना चाहिए। खुराक संकलक को इस अतिरिक्त 8 बाइट की आवश्यकता क्यों है? –

+1

ओह, मुझे मिल गया। यह एक 32-बिट machince है। माफ़ कीजिये।यह 4 बाइट + ईबीपी 4 बाइट + गठबंधन 8 बाइट + बफर 16 –

+1

होना चाहिए i386 और x86-64 सिस्टम वी एबीआई के वर्तमान संस्करणों में 16 बी स्टैक संरेखण ('कॉल' निर्देश से पहले) की आवश्यकता होती है, इसलिए कार्यों को मानने की अनुमति है उस। ऐतिहासिक रूप से, i386 एबीआई को केवल 4 बी संरेखण की आवश्यकता थी। (एबीआई दस्तावेज़ों के लिंक के लिए https://stackoverflow.com/tags/x86/info देखें)। जीसीसी भी पत्ती कार्यों में भी '% esp' गठबंधन रखता है (जो अन्य कार्यों को कॉल नहीं करता है), जब इसे किसी भी स्थान को आरक्षित करना होता है, और यही वह हो रहा है। –

3

मुझे this site मिला, जिसमें पृष्ठ के निचले हिस्से में कुछ अच्छा स्पष्टीकरण है कि स्टैक बड़ा क्यों हो सकता है। 64 बिट मशीन तक अवधारणा को स्केल करें और यह समझा सकता है कि आप क्या देख रहे हैं।

-1

8 बाइट्स वहां हैं क्योंकि पहला निर्देश स्टैक पर% ebp के प्रारंभिक मान को धक्का देता है (64-बिट मानते हुए)।

+1

वापसी पता और आधार सूचक दोनों स्टैक पर धकेल दिए जाते हैं। – dreamlax

11

निर्देशों के एसएसईएक्स परिवार को 128 बाइट वेक्टरों को 16 बाइट्स के साथ गठबंधन करने की आवश्यकता होती है - अन्यथा आपको उन्हें लोड/स्टोर करने की कोशिश कर रहे एक सेगफॉल्ट मिलता है। अर्थात। यदि आप स्टैक पर एसएसई के साथ उपयोग के लिए सुरक्षित रूप से 16-बाइट वैक्टर पास करना चाहते हैं, तो स्टैक को लगातार 16 तक गठबंधन रखा जाना चाहिए। इसके लिए जीसीसी खाते डिफ़ॉल्ट रूप से हैं।

+0

इस मामले के साथ मुझे बहुत कम अनुभव हो सकता है कि आपका जवाब गलत है। लेकिन क्या आप उस उद्देश्य के लिए 'movupd' और इसी तरह ** ** ** naligned निर्देशों का उपयोग नहीं करते हैं (_unaligned_ पैक किए गए डेटा को लोड/संग्रहीत)? जो मैं समझता हूं, उससे आप 'movapd' का उपयोग करने और असाइन किए गए डेटा पर समान निर्देशों का उपयोग करते समय दोषपूर्ण व्यवहार प्राप्त कर सकते हैं, लेकिन असाइन किए जाने वाले डेटा को सामान्य रूप से कोई समस्या नहीं होनी चाहिए। – andreee

1

मैक ओएस एक्स/डार्विन x86 एबीआई को 16 बाइट्स का एक स्टैक संरेखण की आवश्यकता है। लिनक्स, विन 32, फ्रीबीएसडी जैसे अन्य x86 प्लेटफ़ॉर्म पर यह मामला नहीं है ...

+1

वास्तविक एबीआई आवश्यकता यह है कि स्टैक कॉल बाइट्स पर 16 बाइट गठबंधन * हो। *। –

+2

यह सच है, लेकिन चूंकि फ़ंक्शन प्रोग्राम्स/एपिलॉग्स केवल उन स्थानों के बारे में हैं जहां स्टैक पॉइंटर बदल दिया गया है, यह लगभग यह कहने जैसा ही है कि इसे हर समय गठबंधन करने की आवश्यकता है। – Ringding

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