2011-01-25 14 views
17

इस संकलक उत्पादन में, मैं समझने के लिए nopw शिक्षा का मशीन कोड एन्कोडिंग काम करता है कोशिश कर रहा हूँ:AMD64 - nopw असेंबली निर्देश?

00000000004004d0 <main>: 
    4004d0:  eb fe     jmp 4004d0 <main> 
    4004d2:  66 66 66 66 66 2e 0f nopw %cs:0x0(%rax,%rax,1) 
    4004d9:  1f 84 00 00 00 00 00 

वहाँ http://john.freml.in/amd64-nopl पर "nopw" के बारे में कुछ चर्चा है। क्या कोई 4004d2-4004e0 के अर्थ की व्याख्या कर सकता है? ओपोड सूची को देखने से, ऐसा लगता है कि 66 .. कोड बहु-बाइट विस्तार हैं। मुझे लगता है कि जब तक मैंने कुछ घंटों तक ऑपोड सूची को ग्रोक करने की कोशिश नहीं की, तब तक मैं शायद इससे बेहतर जवाब प्राप्त कर सकता हूं।


एएसएम उत्पादन सी ​​में निम्नलिखित (पागल) कोड है, जो एक सरल अनंत लूप करने के लिए नीचे का अनुकूलन से है:

long i = 0; 

main() { 
    recurse(); 
} 

recurse() { 
    i++; 
    recurse(); 
} 

जब gcc -O2 साथ संकलित, संकलक अनंत प्रत्यावर्तन और बारी-बारी से पहचानता है यह एक अनंत लूप में; यह वास्तव में ऐसा करता है, वास्तव में, यह वास्तव में में recurse() फ़ंक्शन को कॉल किए बिना लूप करता है।


संपादक का नोट: एनओपी के साथ पैडिंग फ़ंक्शन अनंत लूप के लिए विशिष्ट नहीं है। यहां एनओपी की लंबाई की एक श्रृंखला है, on the Godbolt compiler explorer.

+0

क्या हम यहां यादृच्छिक जंक पैडिंग देख रहे हैं? –

+1

शायद! मैं वास्तव में नहीं जानता! यह सब की सुंदरता है! WHEEE। असल में, हालांकि, मैं लिंक से मिलता हूं कि प्रोसेसर स्पीड ऑप्टिमाइज़ेशन के लिए एक निर्देश के रूप में एक ब्लॉक लोड कर रहा है, हालांकि 'jmp' के लिए धन्यवाद, यह नहीं है। मुझे बस इसका अर्थ मिलता है। मुझे पता है कि 0x90 क्या है, लेकिन मुझे नहीं पता कि '66 .. ..' के साथ क्या चल रहा है, या यह 72 बिट लंबा क्यों है। –

+1

यह कारण नहीं है, लेकिन आप पाते हैं [मेरा, आपके पास क्या अजीब एनओपी है! - ओल्ड न्यू थिंग] (http://blogs.msdn.com/b/oldnewthing/archive/2011/01/12/10114521.aspx) एक दिलचस्प पढ़ा। – ephemient

उत्तर

20

0x66 बाइट्स "ऑपरेंड-साइज ओवरराइड" उपसर्ग हैं। इनमें से एक से अधिक होने के बराबर है।

0x2e 64-बिट मोड में 'शून्य उपसर्ग' है (यह एक सीएस है: सेगमेंट अन्यथा ओवरराइड करता है - यही कारण है कि यह असेंबली निमोनिक में दिखाई देता है)।

0x0f 0x1f एक एनओपी कि एक ModRM बाइट

0x84ModRM byte है लेता है के लिए एक 2 बाइट opcode है जो 5 अधिक बाइट्स का उपयोग करता है एक को संबोधित मोड के लिए इस मामले में कोड।

कुछ सीपीयू कई उपसर्गों (जैसे तीन से अधिक) के साथ निर्देशों को डीकोड करने में धीमे होते हैं, इसलिए एक एसआईबी + disp32 निर्दिष्ट करता है जो एक मॉडआरएम बाइट पांच और उपसर्ग बाइट्स से अतिरिक्त 5 बाइट्स का उपयोग करने का एक बेहतर तरीका है।

AMD K8 decoders in Agner Fog's microarch pdf:

अनुदेश डिकोडर से प्रत्येक प्रति घड़ी चक्र तीन उपसर्गों संभाल कर सकते हैं। इसका मतलब यह है कि तीन उपसर्गों के साथ तीन निर्देश प्रत्येक को उसी घड़ी चक्र में डीकोड किया जा सकता है। 4-6 उपसर्गों के साथ एक निर्देश डीकोड करने के लिए एक अतिरिक्त घड़ी चक्र लेता है।


अनिवार्य रूप से, उन बाइट्स एक लंबी एनओपी अनुदेश कि वैसे भी निष्पादित हो कभी नहीं होगा रहे हैं। यह सुनिश्चित करने के लिए है कि अगला कार्य 16-बाइट सीमा पर गठबंधन किया गया है, क्योंकि संकलक ने .p2align 4 निर्देश उत्सर्जित किया है, इसलिए असेंबलर एनओपी के साथ गद्देदार है।gcc's default for x86 is
-falign-functions=16
। एनओपी के लिए निष्पादित किया जाएगा, लंबी-एनओपी की इष्टतम पसंद माइक्रोआर्किटेक्चर पर निर्भर करती है। एक माइक्रोआर्किटेक्चर के लिए जो इंटेल सिल्वरमॉन्ट या एएमडी के 8 जैसे कई उपसर्गों पर चोक करता है, 3 उपसर्गों वाले दो एनओपी प्रत्येक को तेजी से डीकोड कर सकते हैं।

ब्लॉग आलेख से संबंधित प्रश्न (http://john.freml.in/amd64-nopl) बताता है कि संकलक एकल-बाइट 0x90 एनओपी निर्देशों के समूह के बजाय एक जटिल एकल एनओपी निर्देश का उपयोग क्यों करता है।

आप एएमडी के तकनीक रेफरी दस्तावेजों में अनुदेश एन्कोडिंग बारे में विवरण प्राप्त कर सकते हैं:

मुख्य रूप में "AMD64 आर्किटेक्चर प्रोग्रामर के मैनुअल माप 3: सामान्य प्रयोजन और सिस्टम निर्देश"। मुझे यकीन है कि x64 आर्किटेक्चर के लिए इंटेल के तकनीकी संदर्भों में एक ही जानकारी होगी (और यहां तक ​​कि अधिक समझने योग्य भी हो सकता है)।

+0

ModRM बाइट का अर्थ है ... http://ref.x86asm.net/coder64.html#x0F1F इस संदर्भ के साथ, Hintable एनओपी के लिए उपयोग किए जाने वाले मॉडआरएम बाइट को सूचीबद्ध करता है: 1. यूएस पेटेंट 5,701,442 2. सैंडपाइल देखें। संगठन - आईए -32 आर्किटेक्चर - ऑपोड समूह। मैंने उनको चेक नहीं किया है, लेकिन यदि आप परवाह करते हैं। – Bahbar

+0

यह एक एनओपी है, इसलिए मॉड/आरएम बाइट * कुछ भी नहीं करता है। यह निर्देशों का एक हिस्सा है कि निर्देशों की एक बड़ी श्रृंखला को इस तरह से अनुमति देने के लिए कि डीकोडर्स जल्दी से डीकोड कर सकें। कुछ सीपीयू पर कई उपसर्गों को डीकोड करना धीमा है, इसलिए बस '66' ऑपरेंड-साइज उपसर्ग 5 बार दोहराएं एक मॉड/आरएम से बहुत खराब है जो एक एसआईबी + disp32 का उपयोग करने वाले एड्रेसिंग मोड के लिए कोड है। –

1

मुझे लगता है कि यह केवल शाखा-देरी निर्देश है।

-3

मुझे विश्वास है कि nopw जंक है - मुझे आपके प्रोग्राम में कभी नहीं पढ़ा जाता है, और इस प्रकार इसे बढ़ाने की आवश्यकता नहीं होती है।

+0

'i' ने विफल होने पर स्टैक आकार की जांच करने का एक सुविधाजनक तरीका दिया। जीडीबी, जहां तक ​​मेरा सीमित ज्ञान जाता है, में "स्टैक का प्रिंट आकार" कुंजी नहीं है। एक बार ऑप्टिमाइज़ेशन स्तर को समाप्त करने के बाद संकलक को इसके बढ़ने को हटाने के लिए और अधिक दिलचस्प है। कार्यक्रम जानबूझकर "पागल" है। –

+0

मेरा मुद्दा यह था कि संकलक ने इसे अनुकूलित किया - क्योंकि आपने कभी मुझे नहीं पढ़ा है। –

+0

प्रश्न इस बारे में नहीं है, हालांकि। सवाल का मुद्दा यह है कि क्यों 'nop' ('nopw') इस तरह से बाहर आते हैं। मानक 'nop' 0x90 है और बस दोहराया गया है। एक अप्रयुक्त चर के रूप में वहां 'i' डालना उद्देश्यपूर्ण और बाहरी रूप से उपयोगी था, भले ही यह कोड में छुआ न हो। –

2

असेंबलर (कंपाइलर नहीं) पैड कोड अगली संरेखण सीमा तक सबसे लंबे समय तक एनओपी निर्देश के साथ कोड फिट बैठता है। यह वही है जो आप देख रहे हैं।