2009-03-23 20 views
37

स्टैक संरेखण क्या है? इसका उपयोग क्यों किया जाता है? क्या इसे संकलक सेटिंग्स द्वारा नियंत्रित किया जा सकता है?"स्टैक संरेखण" क्या है?

एमएसवीसी के साथ ffmpeg पुस्तकालयों का उपयोग करने की कोशिश करते समय इस प्रश्न का विवरण सामना करने वाली समस्या से लिया गया है, हालांकि मुझे वास्तव में क्या रूचि है, यह "स्टैक संरेखण" का एक स्पष्टीकरण है।

विवरण:

  • जब runnig मेरे MSVC कार्यक्रम मैं निम्न त्रुटि प्राप्त avcodec से जोड़ता है जो पालन किया: "। संकलक ढेर चर संरेखित नहीं किया libavcodec miscompiled कर दिया गया है", में एक दुर्घटना के बाद avcodec.dll।
  • avcodec.dll msvc के साथ संकलित नहीं किया गया था, इसलिए मैं यह देखने में असमर्थ हूं कि अंदर क्या हो रहा है।
  • ffmpeg.exe चलाते समय और उसी avcodec.dll का उपयोग करके सबकुछ ठीक से काम करता है।
  • ffmpeg.exe MSVC के साथ संकलित नहीं किया गया था, यह जीसीसी/MinGW (avcodec.dll के रूप में ही)

धन्यवाद का पालन किया गया था

दान

स्मृति में चर के
+1

चूंकि अन्य ने समझाया है कि स्टैक संरेखण क्या है और इसका उपयोग क्यों किया जाता है, मैं सिर्फ "दो कंपाइलर सेटिंग्स द्वारा नियंत्रित किया जा सकता है" _ के संबंध में अपने दो सेंट जोड़ना चाहता हूं। _ _। [यह प्रश्न] देखें (http://stackoverflow.com/questions/5496045/why-is-my-stack-pointer-only-incrementing-in-multiples-of-16?lq=1) – andreee

उत्तर

91

संरेखण (क छोटा इतिहास)।

पिछले कंप्यूटरों में 8 बिट्स डेटाबेस थे। इसका मतलब है कि प्रत्येक घड़ी चक्र 8 बिट्स की जानकारी संसाधित की जा सकती है। जो तब ठीक था।

फिर 16 बिट कंप्यूटर आए। नीचे की संगतता और अन्य मुद्दों के कारण, 8 बिट बाइट रखा गया था और 16 बिट शब्द पेश किया गया था। प्रत्येक शब्द 2 बाइट था। और प्रत्येक घड़ी चक्र 16 बिट्स की जानकारी संसाधित की जा सकती है। लेकिन इसने एक छोटी सी समस्या उत्पन्न की। एक स्मृति मानचित्र पर

आइए नज़र:

+----+ 
|0000| 
|0001| 
+----+ 
|0002| 
|0003| 
+----+ 
|0004| 
|0005| 
+----+ 
| .. | 

प्रत्येक पते पर एक बाइट जो व्यक्तिगत रूप से पहुँचा जा सकता है नहीं है। लेकिन शब्दों को केवल पते पर ही लाया जा सकता है। तो अगर हम 0000 पर एक शब्द पढ़ते हैं, तो हम बाइट्स को 0000 और 0001 पर पढ़ते हैं। लेकिन अगर हम 0001 स्थिति में शब्द पढ़ना चाहते हैं, तो हमें दो पढ़ने की ज़रूरत है। पहले 0000,0001 और फिर 0002,0003 और हम केवल 0001,0002 रखते हैं।

बेशक इसमें कुछ अतिरिक्त समय लगा और इसकी सराहना नहीं की गई। इसलिए उन्होंने संरेखण का आविष्कार किया। इसलिए हम बाइट सीमाओं पर शब्द सीमाओं और बाइट चर पर शब्द चर को संग्रहीत करते हैं।

+----+ 
|0000| B 
|0001| W 
+----+ 
|0002| W 
|0003| 
+----+ 

कौन सा मज़ा नहीं है:

उदाहरण के लिए, अगर हम एक बाइट क्षेत्र (बी) और एक शब्द भी क्षेत्र (डब्ल्यू) (और एक बहुत भोली संकलक) के साथ एक संरचना है, हम निम्नलिखित मिल । लेकिन शब्द संरेखण का उपयोग करते समय हम पाते हैं:

+----+ 
|0000| B 
|0001| - 
+----+ 
|0002| W 
|0003| W 
+----+ 

यहां स्मृति की गति के लिए स्मृति का त्याग किया जाता है।

आप कल्पना कर सकते हैं कि डबल शब्द (4 बाइट्स) या ट्रैक्टर शब्द (8 बाइट्स) का उपयोग करते समय यह और भी महत्वपूर्ण है। यही कारण है कि अधिकांश आधुनिक कंपाइलर्स के साथ आप प्रोग्राम को संकलित करते समय आप किस संरेखण का उपयोग कर रहे हैं चुन सकते हैं।

+3

स्टैक संरेखण का शानदार वर्णन ! –

+0

मैं असेंबली सीखने की कोशिश कर रहा हूं, और मैं संरेखण को समझने के लिए संघर्ष कर रहा हूं। यह पूरी तरह से मेरे सवालों का जवाब! – joek1975

+0

किसी की मदद करने के लिए हमेशा खुश रहें :-)। –

11

आईआईआरसी, स्टैक संरेखण तब होता है जब स्टैक्स पर "संरेखित" पर चर को एक विशेष संख्या में बाइट्स पर रखा जाता है। तो यदि आप 16 बिट स्टैक संरेखण का उपयोग कर रहे हैं, तो स्टैक पर प्रत्येक चर एक बाइट से शुरू होने जा रहा है जो एक फ़ंक्शन के भीतर मौजूदा स्टैक पॉइंटर से 2 बाइट्स का एक बहु है।

इसका मतलब है कि यदि आप एक चर (0 बाइट) जैसे < 2 बाइट्स का उपयोग करते हैं, तो इसके और अगले चर के बीच अप्रयुक्त "पैडिंग" के 8 बिट होंगे। यह परिवर्तनीय स्थानों के आधार पर धारणाओं के साथ कुछ अनुकूलन की अनुमति देता है।

फ़ंक्शंस कॉल करते समय, अगले कार्य में तर्क पारित करने का एक तरीका उन्हें स्टैक पर रखना है (जैसा कि उन्हें सीधे रजिस्टरों में रखने का विरोध किया जाता है)। यहां संरेखण का उपयोग किया जा रहा है या नहीं, यहां महत्वपूर्ण है, क्योंकि कॉलिंग फ़ंक्शन स्टैक पर वेरिएबल्स रखता है, ऑफसेट का उपयोग करके कॉलिंग फ़ंक्शन द्वारा पढ़ा जा सकता है। यदि कॉलिंग फ़ंक्शन वेरिएबल्स को संरेखित करता है, और कॉल किया गया फ़ंक्शन उन्हें गैर-गठबंधन होने की अपेक्षा करता है, तो कॉल किया गया फ़ंक्शन उन्हें नहीं ढूंढ पाएगा।

ऐसा लगता है कि एमएसवीसी संकलित कोड परिवर्तनीय संरेखण के बारे में असहमत है। बंद सभी अनुकूलन के साथ संकलन का प्रयास करें।

+1

आकार (चार) हमेशा 1 बाइट होता है, जो हमेशा कम से कम 8 बिट्स होता है ... बाइट नहीं। संरेखण संकलक मंच पर निर्भर करता है, और (x86, वैसे भी) 32 बिट आर्किटेक्चर के लिए आमतौर पर 4byte है, 64 बिट आर्क के लिए 8byte। – snemarch

+1

धन्यवाद, वास्तव में बाइट के आकार पर एक मस्तिष्क था: पी। मैंने 16 बाइट्स को मनमाना उदाहरण के रूप में चुना था, लेकिन छोटे उदाहरण का उपयोग करके यह बहुत स्पष्ट हो गया है। –

10

कुछ सीपीयू आर्किटेक्चर को विभिन्न डेटाटाइप के विशिष्ट संरेखण की आवश्यकता होती है, और यदि आप इस नियम का सम्मान नहीं करते हैं तो अपवाद फेंक देंगे। मानक मोड में, x86 को बुनियादी डेटा प्रकारों के लिए इसकी आवश्यकता नहीं होती है, लेकिन प्रदर्शन दंड का सामना कर सकते हैं (निम्न स्तर के अनुकूलन युक्तियों के लिए www.agner.org देखें)।

हालांकि, SSE अनुदेश सेट ऑडियो/वीडियो procesing (अक्सर उच्च प्रदर्शन के लिए इस्तेमाल किया) सख्त संरेखण आवश्यकताएं हैं, और यदि आप असंरेखित डेटा पर इसका इस्तेमाल करने का प्रयास अपवाद फेंक देते हैं (जब तक आप उपयोग करते हैं, कुछ प्रोसेसर पर, बहुत धीमे unaligned संस्करण)।

आपका मुद्दा है, जबकि अन्य की उम्मीद कॉल प्राप्त करने वाला जब आवश्यक ढेर संरेखित करने के लिए, शायद है कि एक संकलक फोन करने वाले उम्मीद ढेर गठबंधन रखने के लिए है।

संपादित: के लिए क्यों अपवाद होता है के रूप में, DLL में एक नियमित शायद कुछ अस्थायी ढेर डेटा पर SSE निर्देश का उपयोग करना चाहता है, और विफल रहता है, क्योंकि दो अलग compilers सम्मेलनों बुला पर सहमत नहीं हूं।

2

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

// Some compilers won't align this as it's on the stack... 
int __declspec(align(32)) needsToBe32Aligned = 0; 
// Change to 
static int __declspec(align(32)) needsToBe32Aligned; 
needsToBe32Aligned = 0; 

वैकल्पिक रूप से, एक कंपाइलर स्विच ढूंढें जो ढेर पर चर को संरेखित करता है। स्पष्ट रूप से "__declspec" संरेखण संरेखण मैंने यहां उपयोग किया है जो आपके कंपाइलर का उपयोग नहीं कर सकता है।

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