2009-07-18 11 views
15

हाय मैं disassembled है कुछ कार्यक्रमों (लिनक्स) समझने की कोशिश कर रहा बेहतर यह कैसे काम करता समझने के लिए लिखा था, और मैंने देखा है कि मुख्य कार्य हमेशा साथ शुरू होता है:मुख्य disassembly पहले निर्देश

lea ecx,[esp+0x4] ; I assume this is for getting the adress of the first argument of the main...why ? 
and esp,0xfffffff0 ; ??? is the compiler trying to align the stack pointer on 16 bytes ??? 
push DWORD PTR [ecx-0x4] ; I understand the assembler is pushing the return adress....why ? 
push ebp     
mov ebp,esp 
push ecx ;why is ecx pushed too ?? 

तो मेरे सवाल है: यह सब काम क्यों किया जाता है ??

+1

आप किस कंपाइलर का उपयोग कर रहे हैं, और क्या आप पूरी तरह से पृथक मुख्य सबराउटिन प्रदान कर सकते हैं? – Inshallah

उत्तर

25

मैंने इसे एक जाना पड़ा है

push ebp     
mov ebp,esp 

बाकी मेरे लिए बेकार लगता है ...: रखने के लिए

;# As you have already noticed, the compiler wants to align the stack 
;# pointer on a 16 byte boundary before it pushes anything. That's 
;# because certain instructions' memory access needs to be aligned 
;# that way. 
;# So in order to first save the original offset of esp (+4), it 
;# executes the first instruction: 
lea ecx,[esp+0x4] 

;# Now alignment can happen. Without the previous insn the next one 
;# would have made the original esp unrecoverable: 
and esp,0xfffffff0 

;# Next it pushes the return addresss and creates a stack frame. I 
;# assume it now wants to make the stack look like a normal 
;# subroutine call: 
push DWORD PTR [ecx-0x4] 
push ebp 
mov ebp,esp 

;# Remember that ecx is still the only value that can restore the 
;# original esp. Since ecx may be garbled by any subroutine calls, 
;# it has to save it somewhere: 
push ecx 
+1

+1, यह हो रहा है + एक अच्छा स्पष्टीकरण। 16-बाइट सीमाएं आदर्श हैं क्योंकि उन्हें सिमड (एमएमएक्स/एसएसई/एसएसई 2 इत्यादि) के उपयोग के लिए आवश्यक हैं। यदि आप स्टैक पर गैर-16-बाइट गठबंधन मूल्य पर एक गठबंधन सिमड निर्देश का उपयोग करने का प्रयास करते हैं, तो आप segfault करेंगे। – Falaina

+0

@ फालेना: धन्यवाद! आपके इनपुट को प्रतिबिंबित करने के लिए संपादित किया गया। – Inshallah

5

यह किया जाता है मैं केवल का उपयोग को समझने एक 16-बाइट सीमा के साथ गठबंधन ढेर। कुछ निर्देशों के लिए कुछ डेटा प्रकारों को 16-बाइट सीमा तक गठबंधन करने की आवश्यकता होती है। इस आवश्यकता को पूरा करने के लिए, जीसीसी यह सुनिश्चित करता है कि स्टैक प्रारंभ में 16-बाइट गठबंधन है, और 16 बाइट्स के गुणकों में स्टैक स्पेस आवंटित करता है। इसे -mpreferred-stack-boundary=num विकल्प का उपयोग करके नियंत्रित किया जा सकता है। यदि आप -mpreferred-stack-border = 2 (2 = 4-बाइट संरेखण के लिए) का उपयोग करते हैं, तो यह संरेखण कोड उत्पन्न नहीं होगा क्योंकि स्टैक हमेशा कम से कम 4-बाइट गठबंधन होता है। हालांकि, यदि आपका प्रोग्राम किसी भी प्रकार के डेटा प्रकार का उपयोग करता है जिसके लिए मजबूत संरेखण की आवश्यकता होती है तो आपको परेशानी हो सकती है।

जीसीसी के मैनुअल के अनुसार:

पेंटियम और PentiumPro, पर डबल और लंबी डबल मूल्यों एक 8 बाइट सीमा के अनुरूप किया जाना चाहिए (देखें -malign-डबल) या महत्वपूर्ण रन टाइम प्रदर्शन जुर्माना भुगतना पड़। पेंटियम III पर, स्ट्रीमिंग सिम एक्सटेंशन (एसएसई) डेटा प्रकार __m128 ठीक से काम नहीं कर सकता है अगर यह 16 बाइट गठबंधन नहीं है।

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

यह अतिरिक्त संरेखण अतिरिक्त स्टैक स्पेस का उपभोग करता है, और आम तौर पर कोड आकार बढ़ाता है। कोड जो अंतरिक्ष उपयोग को ढेर करने के लिए संवेदनशील है, जैसे कि एम्बेडेड सिस्टम और ऑपरेटिंग सिस्टम कर्नेल, पसंदीदा संरेखण को कम करने के लिए -mpreferred-stack-border = 2 को कम करना चाहते हैं।

lea भार मूल ढेर सूचक ecx में (main को कॉल करने से पहले से), के बाद से ढेर सूचक संशोधित करने के बारे में है। यह दो उद्देश्यों के लिए प्रयोग किया जाता है:

  1. main कार्य करने के लिए तर्क का उपयोग करने की, क्योंकि वे मूल ढेर सूचक
  2. अपने मूल मूल्य के लिए ढेर सूचक को बहाल करने के सापेक्ष हैं जब main
से लौट रहे
4
lea ecx,[esp+0x4] ; I assume this is for getting the adress of the first argument of  the main...why ? 
and esp,0xfffffff0 ; ??? is the compiler trying to align the stack pointer on 16 bytes ??? 
push DWORD PTR [ecx-0x4] ; I understand the assembler is pushing the return adress....why ? 
push ebp     
mov ebp,esp 
push ecx ;why is ecx pushed too ?? 

यहां तक ​​कि यदि हर निर्देश मनमाने ढंग से गठित ऑपरेंड के बावजूद गति गति के साथ पूरी तरह से काम करता है, तो संरेखण अभी भी प्रदर्शन में वृद्धि करेगा। एक 16-बाइट मात्रा का संदर्भ देने वाले लूप की कल्पना करें जो केवल दो कैश लाइनों को ओवरलैप करता है।अब, कैश में उस छोटे wchar को लोड करने के लिए, दो पूरी कैश लाइनों को बेदखल कर दिया जाना चाहिए, और यदि आपको उसी लूप में उनकी आवश्यकता है तो क्या होगा? कैश रैम की तुलना में बहुत तेज़ है कि कैश प्रदर्शन हमेशा महत्वपूर्ण होता है।

इसके अलावा, आमतौर पर रजिस्टरों में misaligned ऑपरेंड को स्थानांतरित करने के लिए एक गति दंड है। यह देखते हुए कि स्टैक को वास्तविकता दी जा रही है, हम स्वाभाविक रूप से पैरामीटर के लिए स्टैक फ्रेम को पार करने और लौटने के लिए पुरानी संरेखण को सहेजना चाहते हैं।

ecx एक अस्थायी रजिस्टर है इसलिए इसे सहेजा जाना है। इसके अलावा, ऑप्टिमाइज़ेशन स्तर के आधार पर, कुछ फ्रेम लिंकेज ऑप्स जो प्रोग्राम चलाने के लिए कड़ाई से जरूरी नहीं लगते हैं, वे फ्रेम की ट्रेस-तैयार श्रृंखला सेट अप करने के लिए महत्वपूर्ण हो सकते हैं।

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