2014-05-23 16 views
16

मैं की तर्ज पर Arduino के लिए कोड और अन्य हार्डवेयर सी के साथ विधानसभा इनलाइन है, कुछ देखा है:सी कोड के साथ असेंबली इनलाइन कैसे काम करता है?

asm("movl %ecx %eax"); /* moves the contents of ecx to eax */ 
__asm__("movb %bh (%eax)"); /*moves the byte from bh to the memory pointed by eax */ 

कैसे यह वास्तव में कार्य करता है? मुझे एहसास है कि प्रत्येक कंपाइलर अलग है, लेकिन यह सामान्य कारण क्या हैं, और कोई इसका लाभ कैसे उठा सकता है?

उत्तर

9

इनलाइन कोडांतरक कोड सही पूरा इकट्ठे कोड अछूता में और एक टुकड़ा में चला जाता है। आप ऐसा करते हैं जब आपको वास्तव में अपने निर्देश अनुक्रम पर पूर्ण नियंत्रण की आवश्यकता होती है, या हो सकता है कि जब आप ऑप्टिमाइज़र को अपने कोड के साथ अपना रास्ता न दें। शायद आपको हर घड़ी की टिक की जरूरत है। हो सकता है कि आपको घड़ी कोड की सटीक संख्या लेने के लिए अपने कोड की प्रत्येक शाखा की आवश्यकता हो, और ऐसा करने के लिए आप एनओपी के साथ पैड करें।

किसी भी मामले में, कारण किसी को ऐसा करने के लिए चाहते हो सकता है की बहुत सारी है, लेकिन तुम सच में जानना आप क्या कर रहे जरूरत है। कोड के ये भाग आपके कंपाइलर के लिए बहुत अपारदर्शी होंगे, और यदि आप कुछ खराब कर रहे हैं तो आपको इसकी कोई चेतावनी नहीं मिलेगी।

+2

"आपको वास्तव में यह जानने की जरूरत है कि आप क्या कर रहे हैं" पर अनुवर्ती करने के लिए। सावधानी के शब्द कि असेंबली की सटीक रेखाएं जिन्हें आप इनलाइन करना चाहते हैं, हमेशा संकलक द्वारा बिल्कुल सम्मानित नहीं होते हैं। मैंने सूक्ष्म परिवर्तन करने वाले कंपाइलर्स का अनुभव किया है। यह सुनिश्चित करने के लिए संकलन के बाद हमेशा अलग-अलग हिस्सों पर एक अच्छा नज़र डालें कि यह वास्तव में क्या कर रहा है। – BabaBooey

+1

मेरा मानना ​​है कि यदि आप 'अस्थिर' विनिर्देशक भी जोड़ते हैं, तो उन्हें बिल्कुल सम्मानित किया जाता है। '__asm__ अस्थिर (" instrs ");' – slugonamission

+0

आपको यह भी जानने की ज़रूरत है कि कौन सा प्रोसेसर (परिवार) आपका कोड चल रहा है और, कुछ मामलों में, कौन सा मेमोरी मॉडल। एएनएसआई-सी लगभग किसी भी प्रोसेसर और ओएस के लिए संकलित किया जा सकता है लेकिन एएसएम निर्देश * पोर्टेबल नहीं हैं। –

4

आमतौर पर संकलक सिर्फ सही अपने उत्पन्न कोडांतरक उत्पादन में कोडांतरक निर्देश डाल देंगे। और यह परिणामों के संबंध में यह नहीं करेगा।

उदाहरण के लिए, इस कोड में अनुकूलक प्रति प्रचार, प्रदर्शन जिससे यह देखता है कि y = एक्स, तो z = y है। इसलिए यह ज़ेड = एक्स को ज़ेड = एक्स के साथ बदल देता है, उम्मीद है कि इससे इसे और ऑप्टिमाइज़ेशन करने की अनुमति मिल जाएगी। हाउवर, यह नहीं पता है कि मैंने एक्स के मूल्य के साथ औसत समय में गड़बड़ की है।

char x=6; 
char y,z; 

y=x;     // y becomes 6 

_asm      
    rrncf x, 1  // x becomes 3. Optimiser doesn't see this happen! 
_endasm 

z=y;     // z should become 6, but actually gets 
        // the value of x, which is 3 

इस के आसपास पाने के लिए, आप अनिवार्य रूप से इस चर के लिए इस अनुकूलन प्रदर्शन करने के लिए नहीं अनुकूलक बता सकते हैं।

volatile char x=6; // Tell the compiler that this variable could change 
        // all by itself, and any time, and therefore don't 
        // optimise with it. 
char y,z; 

y=x;     // y becomes 6 

_asm      
    rrncf x, 1  // x becomes 3. Optimiser doesn't see this happen! 
_endasm 

z=y;     // z correctly gets the value of y, which is 6 
+4

"अस्थिर चार वाई, जेड;" अनुकूलन त्रुटि को रोकें? –

+0

@ स्कॉटसेडमैन: हाँ, विशेष रूप से 'अस्थिर चार y'। कंपाइलर वास्तविक 'y' असाइन करना सुनिश्चित करेगा, न कि अनुकूलित 'मान जिसे हाल ही में एक्स में लिखा गया था, और फिर y'। केवल 'z' अस्थिर बनाना ही मदद नहीं करेगा। –

3

एएसएम ("") और __asm__ दोनों वैध उपयोग कर रहे हैं। मूल रूप से, आप __asm__ का उपयोग कर सकते हैं कि कीवर्ड एएसएम अपने कार्यक्रम में कुछ के साथ विरोध करता है। आप एक से अधिक निर्देश है, तो आप दोहरे उद्धरण में प्रत्येक पंक्ति में एक लिख सकते हैं, और यह भी एक '\ n' और '\ t' अनुदेश के प्रत्यय। ऐसा इसलिए है क्योंकि जीसीसी प्रत्येक निर्देश को स्ट्रिंग के रूप में (जीएएस) के रूप में भेजता है और न्यूलाइन/टैब का उपयोग करके आप असेंबलर को सही रूप से स्वरूपित रेखाएं भेज सकते हैं। आपके प्रश्न में कोड स्निपेट मूल इनलाइन है।

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

__asm__ ("movl %eax, %ebx\n\t" 
      "movl $56, %esi\n\t" 
      "movl %ecx, $label(%edx,%ebx,$4)\n\t" 
      "movb %ah, (%ebx)"); 

सूचना है कि '\ n \ t' पिछले छोड़कर प्रत्येक पंक्ति के अंत में, और प्रत्येक पंक्ति उद्धरण में संलग्न है।ऐसा इसलिए है क्योंकि जीसीसी ने प्रत्येक को एक स्ट्रिंग के रूप में निर्देश के रूप में भेज दिया है जैसा कि मैंने पहले उल्लेख किया था। न्यूलाइन/टैब संयोजन की आवश्यकता है ताकि लाइनों को सही प्रारूप के अनुसार खिलाया जा सके।

+0

यह जीसीसी के लिए कितना विशिष्ट है? –

+0

यह एक उदाहरण ** 'as' ** assembler है जो जीएनयू सी कंपाइलर बैकएंड के रूप में उपयोग करता है। और यह assmbler ** एटी एंड टी वाक्यविन्यास ** का उपयोग करता है। – gbudan

+0

कुछ सुधार: 1) यदि आप आईएसओ मानकों को संकलित कर रहे हैं तो एएसएम के बजाय __asm__ भी आवश्यक है। 2) जबकि कुछ असेंबलरों द्वारा '\ t' की आवश्यकता हो सकती है, बाकी के लिए यह आपके एएसएम आउटपुट को सुंदर बनाता है। 3) मूल बनाम विस्तारित आपके विवरण सही हैं, हालांकि जीसीसी के लिए आपके द्वारा पोस्ट किया गया नमूना "मूल" "विस्तारित" नहीं है। बुनियादी और विस्तारित दस्तावेज़ों को https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html पर देखें –

4

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

असेंबली कोड के लिए सबसे आम उपयोग विशेष प्रोसेसर निर्देशों का उपयोग करना है जो संकलक उत्पन्न करने में सक्षम नहीं है। उदाहरण के लिए, एक महत्वपूर्ण खंड के लिए इंटरप्ट को अक्षम करना, प्रोसेसर सुविधाओं को नियंत्रित करना (कैश, एमएमयू, एमपीयू, पावर मैनेजमेंट, सीपीयू क्षमताओं की पूछताछ, ...), कॉप्रोसेसरों और हार्डवेयर परिधीय (जैसे inb/outb x86 पर निर्देश) आदि का उपयोग करना, आप शायद ही कभी asm("movl %ecx %eax") खोजें, क्योंकि यह सामान्य प्रयोजन रजिस्टरों को प्रभावित करता है कि इसके आसपास सी कोड भी उपयोग कर रहा है, लेकिन asm("mcr p15, 0, 0, c7, c10, 5") जैसे कुछ का उपयोग (एआरएम पर डेटा मेमोरी बाधा) है। OSDev wiki में कोड स्निपेट के साथ कई उदाहरण हैं।

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

असेंबली कोड स्मृति या गति के लिए कोड के छोटे बिट्स को अनुकूलित करने के लिए भी उपयोगी है। चूंकि कंपाइलर स्मार्ट हो रहे हैं, यह आजकल एप्लिकेशन स्तर पर शायद ही प्रासंगिक है, लेकिन यह अभी भी एम्बेडेड दुनिया में प्रासंगिक है।

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

अधिकांश सी कंपाइलर इनलाइन असेंबली का समर्थन करते हैं, लेकिन वाक्यविन्यास भिन्न होता है। यह आमतौर पर कीवर्ड asm, _asm, __asm या __asm__ द्वारा प्रस्तुत किया जाता है। असेंबली कोड के अलावा, इनलाइन असेंबली निर्माण में अतिरिक्त कोड हो सकता है जो आपको असेंबली और सी के बीच मूल्यों को पारित करने की अनुमति देता है (उदाहरण के लिए, स्थानीय चर के मूल्य को प्रविष्टि पर एक रजिस्टर में कॉपी किया गया है), या घोषित करने के लिए कि विधानसभा कोड clobbers या कुछ रजिस्टरों को संरक्षित करता है।

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