2016-03-17 7 views
7

मैं लिनक्स कर्नेल में एक अप्रासंगिक मुद्दा डीबग कर रहा था और etcd प्रक्रिया को देखा, जिसे पर्यवेक्षक द्वारा प्रबंधित किया गया था, बार-बार पेज गलती अपवाद को मार रहा था और SIGSEGV प्राप्त कर रहा था।कंपाइलर द्वारा उत्पन्न असेंबली कोड में यह पैटर्न क्या है?

मैं उत्सुक हो गया और कार्यक्रम डिसअसेंबल करने objdump इस्तेमाल किया, और दोषयुक्त amd64 अनुदेश पाया जा करने के लिए:

89 04 25 00 00 00 00 mov %eax,0x0 

मैं तो एक नमस्ते दुनिया कार्यक्रम के disassembly को देखा। मैंने कंपाइलर द्वारा उत्पन्न कोड में एक बहुत ही सामान्य पैटर्न देखा, जो कि एक समारोह के अंत में है, ret के ठीक बाद, mov पर jmp फ़ंक्शन में वापस आ गया है। उदाहरण के लिए,

0000000000400c00 <main.main>: 
    400c00:  64 48 8b 0c 25 f0 ff mov %fs:0xfffffffffffffff0,%rcx 
    400c07:  ff ff 
     ... 
    400c4b:  48 83 7c 24 48 00  cmpq $0x0,0x48(%rsp) 
    400c51:  74 59     je  400cac <main.main+0xac> 
    400c53:  48 c7 04 24 c0 fc 47 movq $0x47fcc0,(%rsp) 
    400c5a:  00 

     ... 
    400cab:  c3      retq 
    400cac:  89 04 25 00 00 00 00 mov %eax,0x0 
    400cb3:  eb 9e     jmp 400c53 <main.main+0x53> 

क्या यह कुछ चाल चलकर खेला जाता है? यदि ऐसा है, तो यह कैसे काम करता है? मैं 0x400c51 पर अनुमान लगा रहा हूं कि यह 0x400cac पर कूदता है, SIGSEGV ट्रिगर करता है, जिसे संभाला जाता है और फिर अगला निर्देश 0x400c53 पर वापस चला जाता है।

+2

'mov% eax, 0x0' किसी रजिस्टर को तुरंत स्थानांतरित नहीं करता है। यह एक रजिस्टर को 0 पर ले जाता है (जब तक कि किसी बिंदु पर कोई फिक्सअप नहीं किया गया था जो किसी और चीज़ के साथ 0 को प्रतिस्थापित करता है)। यदि आप 'eax' को तत्काल 0 (जो इकट्ठा नहीं करेंगे) में स्थानांतरित करने का प्रयास करना चाहते हैं तो आप 'mov% eax, $ 0' (एक डॉलर चिह्न के साथ) लिखेंगे। – Michael

+0

@ माइकल, सुधार के लिए धन्यवाद। मुझे भ्रम हो गया। –

+0

कोई कंपाइलर अनुकूलित मोड में mov द्वारा 0 पर एक रजिस्टर सेट करेगा। वे ['xor reg, reg'] का उपयोग करेंगे (http://stackoverflow.com/q/33666617/995714) –

उत्तर

1

मैं जाओ डेवलपर्स से कुछ जवाब मिल गया: https://groups.google.com/forum/#!topic/golang-nuts/_7yio3ZfVBE

असल में, इस पद्धति अप्रचलित कार्यान्वयन में जाँच नहीं के बराबर है। उद्धृत रथल का जवाब है।

यदि सूचक शून्य है, तो यह एक निर्देश पर कूदता है जो गलती उत्पन्न करता है। उस गलती का उपयोग एक शून्य पीआरटी आतंक शुरू करने के लिए किया जाता है।

यह एक सुंदर अक्षम कोड अनुक्रम है। Jmps कभी भी प्रतीत होता है। हालिया गो संस्करण में अपग्रेड करें और आप देखेंगे कि यह में सुधार हुआ है।

+1

जीसीसी अक्सर सी में 'if' कथन के शरीर के लिए एक समारोह में पहले' ret' के बाद कोड के छोटे ब्लॉक रखता है। इसलिए जब स्थिति सही होती है, तो यह वहां नीचे कूद जाती है और कुछ करता है, फिर वापस कूदता है। यह सच्चा मामला अधिक कुशल बनाता है, क्योंकि कोई सशर्त शाखा नहीं है और बिना शर्त शाखा है। ऐसा लगता है कि गो कंपाइलर कोड के लिए उसी संरचना का उपयोग करता था जो क्रैश करने के लिए था, वापस नहीं। यही मेरा अनुमान है कि यह पैटर्न पहली जगह क्यों अस्तित्व में था: जीसीसी के लिए कोड बनाना था अगर 'अगर (शून्य सूचक) आतंक' –

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

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