अन्य उत्तर केवल एक एनओपी पर विचार कर रहे हैं जो वास्तव में किसी बिंदु पर निष्पादित होता है - जिसका उपयोग आमतौर पर किया जाता है, लेकिन यह एनओपी का एकमात्र उपयोग नहीं है।
गैर निष्पादित करने एनओपी जब कोड है कि समझौता किया जा सकता है लेखन भी बहुत उपयोगी है - मूल रूप से के लिए, आप पैड में कुछ NOPs साथ समारोह के बादRET
(या इसी तरह अनुदेश)। जब आपको निष्पादन योग्य पैच करना होता है, तो आप आसानी से मूल से शुरू होने वाले फ़ंक्शन में अधिक कोड जोड़ सकते हैं RET
और उन एनओपी में से कई का उपयोग कर सकते हैं, जैसे आपको ज़रूरत है (जैसे लंबी कूद या इनलाइन कोड के लिए) और दूसरे के साथ परिष्करण RET
।
इस उपयोग के मामले में, कोई भी कभी भी NOP
निष्पादन की उम्मीद नहीं करता है । एकमात्र बिंदु निष्पादन योग्य को पैच करने की अनुमति है - एक सैद्धांतिक गैर-गद्देदार निष्पादन योग्य में, आपको वास्तव में फ़ंक्शन के कोड को स्वयं बदलना होगा (कभी-कभी यह मूल सीमाओं को फिट कर सकता है, लेकिन अक्सर आपको किसी भी तरह से कूदने की आवश्यकता होगी ) - यह एक बहुत अधिक जटिल है, विशेष रूप से मैन्युअल रूप से लिखित विधानसभा या एक अनुकूलन कंपाइलर पर विचार करना; आपको जंप और ऐसे ही निर्माणों का सम्मान करना होगा जो कोड के कुछ महत्वपूर्ण अंश पर इंगित कर सकते हैं। सब सब में, बहुत मुश्किल।
बेशक, पुराने जमाने में यह बहुत अधिक उपयोग किया जाता था, जब इन छोटे और ऑनलाइन जैसे पैच बनाने के लिए उपयोगी था । आज, आप सिर्फ एक recompiled बाइनरी वितरित करेंगे और इसके साथ किया जाएगा। अभी भी कुछ ऐसे लोग हैं जो पैचिंग NOPs का उपयोग करते हैं (निष्पादित या नहीं, और हमेशा शाब्दिक नहीं NOP
- उदाहरण के लिए, Windows MOV EDI, EDI
ऑनलाइन पैचिंग के लिए उपयोग करता है - यह उसी तरह है जहां आप सिस्टम लाइब्रेरी को अपडेट कर सकते हैं, जबकि सिस्टम वास्तव में चल रहा है, बिना पुनरारंभ की आवश्यकता के)।
तो आखिरी सवाल यह है कि किसी चीज़ के लिए एक समर्पित निर्देश क्यों है जो वास्तव में कुछ भी नहीं करता है?
- यह एक वास्तविक निर्देश है - जब डिबगिंग या विधानसभा को सौंपना महत्वपूर्ण है। जैसे निर्देश
MOV AX, AX
बिल्कुल वैसा ही करेंगे, लेकिन इरादे को इतनी स्पष्टता से इंगित न करें।
- गद्दी - "कोड" जो कि कोड के समग्र प्रदर्शन को बेहतर बनाने के लिए है जो कि संरेखण पर निर्भर करता है। यह कभी निष्पादित करने के लिए नहीं है। कुछ डिबगर बस अपनी असहमति में NOPs को छिपाते हैं।
- यह संकलक के अनुकूलन के लिए अधिक स्थान देता है - फिर भी उपयोग किया जाने वाला पैटर्न यह है कि आपको संकलन के दो चरण मिल गए हैं, पहला सरल है और बहुत सारे अनावश्यक असेंबली कोड का उत्पादन कर रहा है, जबकि दूसरा साफ करता है, पते के संदर्भों को फिर से बताता है और हटाता है बाहरी निर्देश। यह अक्सर JIT- संकलित भाषाओं में भी देखा जाता है - .NET के IL और JVM के बाइट-कोड दोनों का उपयोग
NOP
बहुत अधिक है; वास्तविक संकलित असेंबली कोड अब उन नहीं है। यह ध्यान दिया जाना चाहिए कि वे x86- NOP
s नहीं हैं , हालांकि।
- यह पढ़ने के लिए ऑनलाइन डिबगिंग दोनों को आसान बनाता है (प्री-
NOP
जीम्ड मेमोरी सभी होगी- s, असंतुष्ट को पढ़ने में बहुत आसान बनाता है) और हॉट-पैचिंग के लिए (हालांकि मैं अब तक एडिट और विजुअल स्टूडियो में जारी रखना पसंद करता हूं: P)।
NOP को निष्पादित करने के लिए, कुछ और बिंदु हैं:
- प्रदर्शन, ज़ाहिर है - यह 8085 में ऐसा क्यों नहीं था, लेकिन यहां तक कि 80486 में पहले से ही एक पाइपलाइन किए गए अनुदेश निष्पादन था, जो थोड़ा पेचीदा "कुछ भी नहीं" करता है।
- जैसा कि देखा गया है
MOV EDI, EDI
, शाब्दिक की तुलना में अन्य प्रभावी NOP हैं NOP
। MOV EDI, EDI
x86 पर 2-बाइट NOP के रूप में सर्वश्रेष्ठ प्रदर्शन है। यदि आपने दो NOP
एस का उपयोग किया है , तो निष्पादित करने के लिए दो निर्देश होंगे।
संपादित करें:
वास्तव में, @DmitryGrigoryev के साथ चर्चा ने मुझे इस बारे में थोड़ा और सोचने के लिए मजबूर किया, और मुझे लगता है कि यह इस प्रश्न / उत्तर के लिए एक मूल्यवान अतिरिक्त है, इसलिए मुझे कुछ अतिरिक्त बिट्स जोड़ने दें:
पहले, बिंदु, स्पष्ट रूप से - एक निर्देश क्यों होगा जो कुछ पसंद करता है mov ax, ax
? उदाहरण के लिए, आइए 8086 मशीन कोड के मामले को देखें (386 मशीन कोड से भी पुराना):
- Opcode के साथ एक समर्पित NOP निर्देश है
0x90
। यह अभी भी समय है जब कई लोगों ने विधानसभा में लिखा, आप पर ध्यान दें। यहां तक कि अगर कोई समर्पित NOP
निर्देश नहीं था , तब भी NOP
कीवर्ड (अन्य नाम / mnemonic) अभी भी उपयोगी होगा और उस पर मैप करेगा।
MOV
वास्तव में जैसे निर्देश कई अलग-अलग opcodes को मैप करते हैं, क्योंकि जो समय और स्थान को बचाता है - उदाहरण के लिए, mov al, 42
" al
रजिस्टर करने के लिए तत्काल बाइट ले जाएं ", जो कि "तत्काल" तर्क होने के नाते 0xB02A
( 0xB0
ओपोड 0x2A
होने के नाते) अनुवाद करता है। ताकि दो बाइट्स लगें।
- इसके लिए कोई शॉर्टकट ओपकोड नहीं है
mov al, al
(क्योंकि यह मूल रूप से करने के लिए एक बेवकूफी है), इसलिए आपको mov al, rmb
अधिभार ("रजिस्टर या मेमोरी") का उपयोग करना होगा । यह वास्तव में तीन बाइट्स लेता है । (हालांकि यह संभवतः कम विशिष्ट का उपयोग करेगा mov rb, rmb
, जिसके लिए केवल दो बाइट्स लेने चाहिए mov al, al
- तर्क बाइट का उपयोग स्रोत और लक्ष्य रजिस्टर दोनों को निर्दिष्ट करने के लिए किया जाता है; अब आप जानते हैं कि 8086 में केवल 8 रजिस्टर क्यों थे: डी)। तुलना करें NOP
, जो एक एकल बाइट अनुदेश है! यह मेमोरी और समय पर बचाता है, क्योंकि 8086 में मेमोरी पढ़ना अभी भी काफी महंगा था - टेप या फ्लॉपी या कुछ और से उस प्रोग्राम को लोड करने का उल्लेख नहीं करना।
तो कहाँ से xchg ax, ax
आता है? आपको बस अन्य xhcg
निर्देशों के opcodes को देखना होगा । आप देखेंगे 0x86
, 0x87
और अंत में, 0x91
- 0x97
। तो इसके nop
साथ ऐसा 0x90
लगता है जैसे एक बहुत अच्छा फिट है xchg ax, ax
(जो, फिर से, एक xchg
"अधिभार" नहीं है - आपको xchg rb, rmb
दो बाइट्स में उपयोग करना होगा )। और वास्तव में, मुझे पूरा यकीन है कि यह उस समय की सूक्ष्म वास्तुकला का एक अच्छा पक्ष-प्रभाव था - अगर मैं सही ढंग से याद करता हूं, तो 0x90-0x97
"xchg, रजिस्टरों पर अभिनय करना ax
और " ax
- di
( ऑपरेंड सममित होने के कारण, इसने आपको पूरी रेंज दी, जिसमें nop भी शामिल है xchg ax, ax
; ध्यान दें कि ऑर्डर है ax, cx, dx, bx, sp, bp, si, di
- bx
बाद है dx
,ax
; याद रखें, रजिस्टर नाम वर्णक्रमीय हैं, आदेशित नाम नहीं हैं - संचायक, काउंटर, डेटा, आधार, स्टैक पॉइंटर, बेस पॉइंटर, सोर्स इंडेक्स, गंतव्य सूचकांक)। उसी दृष्टिकोण का उपयोग अन्य ऑपरेंड के लिए भी किया जाता था, उदाहरण के लिए mov someRegister, immediate
सेट। एक तरह से, आप इस बारे में सोच सकते हैं जैसे कि ओपोड वास्तव में एक पूर्ण बाइट नहीं था - अंतिम कुछ बिट्स "वास्तविक" ओपेरा के लिए "एक तर्क" हैं।
यह सब कहा, x86 पर, nop
एक वास्तविक निर्देश माना जा सकता है, या नहीं। मूल माइक्रो-आर्किटेक्चर ने इसे एक वेरिएंट के रूप में माना था xchg
यदि मैं सही तरीके से याद करता हूं, लेकिन इसे वास्तव nop
में विनिर्देश में नामित किया गया था । और चूंकि xchg ax, ax
वास्तव में एक निर्देश के रूप में कोई मतलब नहीं है, आप देख सकते हैं कि 8086 के डिजाइनरों ने निर्देश डिकोडिंग में ट्रांजिस्टर और रास्ते पर कैसे बचाया, इस तथ्य का दोहन करके कि 0x90
प्राकृतिक रूप से किसी चीज़ का पूरी तरह से "नॉपी" होना।
दूसरी ओर, i8051 के लिए पूरी तरह से डिज़ाइन किया गया ओपकोड है nop
- 0x00
। किंदा व्यावहारिक। अनुदेश डिजाइन मूल रूप से संचालन के लिए उच्च निबल और ऑपरेंड के चयन के लिए कम निबल उपयोग कर रहा है - उदाहरण के लिए, add a
है 0x2Y
, और 0xX8
इसका मतलब है "रजिस्टर 0 प्रत्यक्ष" है, तो 0x28
है add a, r0
। सिलिकॉन पर बहुत बचत होती है :)
मैं अभी भी चल सकता हूं, क्योंकि सीपीयू डिजाइन (संकलक डिजाइन और भाषा डिजाइन का उल्लेख नहीं करना) काफी व्यापक विषय है, लेकिन मुझे लगता है कि मैंने कई अलग-अलग दृष्टिकोण दिखाए हैं जो डिजाइन में बहुत अच्छी तरह से गए हैं।