C से विधानसभा तक


16

मान लीजिए कि हमारे पास avr-8bit के लिए C कोड का निम्नलिखित टुकड़ा है:

int v1=1;
int v2=2;
v2=v2+v1;

मुझे निम्नलिखित जुमले की उम्मीद थी

ldi r18, 1;
ldi r19, 2;
add r19, r18;

लेकिन उसके बाद मैं भागा:

avr-gcc -mmcu=atmega2560 Test.c -o Test.elf

तथा

avr-objdump -S Test.elf > Test.lss

मैं निम्नलिखित जुदा हो गया

    ldi r24, 0x01   ; 1
    ldi r25, 0x00   ; 0
    std Y+2, r25    ; 0x02
    std Y+1, r24    ; 0x01
    ldi r24, 0x02   ; 2
    ldi r25, 0x00   ; 0
    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03
    ldd r18, Y+3    ; 0x03
    ldd r19, Y+4    ; 0x04
    ldd r24, Y+1    ; 0x01
    ldd r25, Y+2    ; 0x02
    add r24, r18
    adc r25, r19
    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03

क्या कोई ऐसा है जो असहमति के परिणाम को समझने में मेरी मदद कर सकता है?

संपादित करें: चार का उपयोग कर विधानसभा बन जाते हैं:

ldi r24, 0x01
std Y+1, r24
ldi r24, 0x02
std Y+2, r24
ldd r25, Y+2
ldd r24, Y+1
add r24, r25
std Y+2, r24

जब एसटीडी निर्देश है?

जवाबों:


20

संक्षिप्त उत्तर: आपके रजिस्टर 8-बिट हैं और आपके मान 16-बिट हैं। इसलिए यह उन्हें दो टुकड़ों में संभाल रहा है।

लंबा जवाब:

    ldi r24, 0x01   ; 1
    ldi r25, 0x00   ; 0

8-बिट रजिस्टरों r24, r25 में 16-बिट वैल्यू 1 को स्टोर करें।

    std Y+2, r25    ; 0x02
    std Y+1, r24    ; 0x01

इसे स्टैक स्थानों Y + 1, Y + 2 पर संग्रहीत करें।

    ldi r24, 0x02   ; 2
    ldi r25, 0x00   ; 0

16-बिट मान 2 को 8-बिट रजिस्टरों r24, r25 में स्टोर करें।

    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03

इसे स्टैक स्थानों Y + 3, Y + 4 पर संग्रहीत करें।

    ldd r18, Y+3    ; 0x03
    ldd r19, Y+4    ; 0x04
    ldd r24, Y+1    ; 0x01
    ldd r25, Y+2    ; 0x02

उन्हें स्टैक से वापस (r18, r19) और (r24, r25) पर कॉपी करें

    add r24, r18
    adc r25, r19

(R18, r19) को (r24, r25), दूसरे जोड़ पर ले जाने सहित जोड़ें

    std Y+4, r25    ; 0x04
    std Y+3, r24    ; 0x03

इसे वापस स्टैक पर स्टोर करें।

अपनी मूल असेंबली प्राप्त करने के लिए, दो चीजों की कोशिश करें:

  • "चार" चर का उपयोग करें
  • "-O2" संकलक विकल्प का उपयोग करें

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

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


धन्यवाद! यह अब और अधिक स्पष्ट है! कृपया प्रश्न में मेरा संपादन खोजें।
डार्ककॉफी

1
मेरा संपादन देखें। कोशिश -O2 भी। शायद -O3, हालांकि वह टूटे हुए कोड का उत्पादन कर सकता है।
pjc50

3
बहुत से एम्बेडेड कोड मैं अतिरिक्त प्रकारों को परिभाषित करने के लिए काम करता हूं जो कि उनके आकार के लिए विशिष्ट हैं, जैसे कि अहस्ताक्षरित ints के लिए "uint8, uint16, uint32"। इस तरह से आप हमेशा जानते हैं कि आप किस तरह के वेरिएबल के साथ काम कर रहे हैं। विशेष रूप से छोटे एम्बेडेड, हस्ताक्षरित, फ्लोट में, अपरिभाषित आकार / हस्ताक्षर के "int" सभी में आपको सीपीयू चक्रों का सबसे अच्छा खर्च होगा और इससे गंभीर कीड़े पैदा होंगे।
जॉन यू

वास्तविक संकलक ने लगभग 10-15 साल पहले इस तरह का व्यवहार करना बंद कर दिया था। रजिस्टर आवंटन समस्या ज्यादातर हल हो गई है और संकलक इसे बहुत अच्छे हैं। वे वास्तव में जानते हैं कि कब एक चर स्टैक पर होना चाहिए, और जब यह एक रजिस्टर में हो सकता है, चाहे वह इसे स्थानांतरित करने के प्रयास के लायक हो, और ऐसा करने के लिए कब। बहीखाता संकलित समय पर किया जाता है, और संकलक के पास खुद की गीगाबाइट मेमोरी होती है। स्पष्ट कारणों के लिए बड़ा अपवाद डिबग मोड है, लेकिन फिर सब कुछ स्टैक पर है।
16

@ pjc50 -O3टूटे हुए कोड का उत्पादन कर सकता है? [उद्धरण वांछित] (और नहीं, सी कोड जो अपरिभाषित व्यवहार को आमंत्रित करता है और फिर कुछ अनुकूलन सेटिंग के साथ टूटता है वह गिनती नहीं करता है)
२२:०२ पर marcelm

4

जैसा कि मैंने कुछ उदाहरण कोड पाया मैं अपनी टिप्पणी का उत्तर दूंगा - अन्य लोगों ने पहले ही समस्या बताई है।

बहुत से एम्बेडेड कोड मैं अतिरिक्त प्रकारों को परिभाषित करने के लिए काम करता हूं, जो उनके आकार के लिए विशिष्ट हैं, जैसे कि अहस्ताक्षरित ints के लिए "uint8, uint16, uint32"। इस तरह से आप हमेशा जानते हैं कि आप किस तरह के वेरिएबल के साथ काम कर रहे हैं। विशेष रूप से छोटे एम्बेडेड, हस्ताक्षरित, फ्लोट में, अपरिभाषित आकार / हस्ताक्षर के "int" सभी में आपको सीपीयू चक्रों का सबसे अच्छा खर्च होगा और सबसे खराब तरीके से गंभीर कीड़े पैदा होंगे।

यहां हमारा वर्तमान # विकास है:

/*
 * Example - the basic data types from our embedded code
 */
typedef unsigned char       uint8;  /*  8 bits */
typedef unsigned short int  uint16; /* 16 bits */
typedef unsigned long int   uint32; /* 32 bits */

typedef char                int8;   /*  8 bits */
typedef short int           int16;  /* 16 bits */
typedef int                 int32;  /* 32 bits */

typedef volatile int8       vint8;  /*  8 bits */
typedef volatile int16      vint16; /* 16 bits */
typedef volatile int32      vint32; /* 32 bits */

typedef volatile uint8      vuint8;  /*  8 bits */
typedef volatile uint16     vuint16; /* 16 bits */
typedef volatile uint32     vuint32; /* 32 bits */

3
अच्छा विचार; uint8_t और दोस्त अब मानक का हिस्सा हैं: stackoverflow.com/questions/16937459/…
pjc50

कितना आसान है! हम थोड़े को एक प्रोजेक्ट के साथ विरासत में मिला है जो C89 था, इसलिए यह जानना अच्छा है कि एक आधिकारिक संस्करण है।
जॉन यू

2

आपका C कोड 16bit पूर्णांक चर (int) का उपयोग करता है। कंपाइलर आपके दिमाग को नहीं पढ़ सकता है, इसलिए यह ठीक उसी तरह संकलित करता है जो स्रोत फ़ाइल में है। इसलिए, यदि आप 8bit चर चाहते हैं, तो आपको संबंधित प्रकार का उपयोग करना होगा।

नतीजतन आप अभी भी स्मृति में मूल्यों को संग्रहीत करेंगे (हालांकि अधिक सरल)। मैं सी में इतना अच्छा नहीं हूं, लेकिन आईएमएचओ, कुछ रजिस्टर में वेरिएबल को असाइन करने के लिए कुछ विकल्प हैं, अगर आप चाहते हैं कि कुछ चर रैम के बजाय रजिस्टरों में हों। कुछ इस तरह:

register unsigned char VARNAME asm("r3");

ध्यान दें कि इस तरह के ट्रिक्स के लिए सभी रजिस्टर उपलब्ध नहीं हैं।

तो, निष्कर्ष? विधानसभा में अपने कार्यक्रम लिखें। वे हमेशा पढ़ने / समर्थन के लिए छोटे, तेज और आसान होंगे।


असेंबली सी की तुलना में पढ़ना आसान है?
डेक्सट्राब

@ dext0rb - हां। बेशक अगर आप दोनों को अच्छी तरह से जानते हैं। यदि आप केवल सी जानते हैं, तो विधानसभा और किसी भी अन्य भाषाओं को पढ़ना मुश्किल होगा।
जॉन्फाउंड

मुझे अंतिम बिंदु से असहमत होना पड़ता है, कोडांतरक में लिखे गए प्रोग्राम पढ़ने में बहुत कठिन होते हैं। बस ऊपर दिए गए सोर्स कोड की तुलना करें। C कोड बहुत अधिक स्पष्ट और छोटा है, साथ ही इसका इरादा भी है। यह अंतर केवल बढ़ता है क्योंकि संरचना का उपयोग किया जाता है।
soandos

@soandos - C कोड छोटा है, हाँ। स्पष्ट? मुझे यकीन नहीं है। यदि ऐसा था, तो ऊपर दिए गए प्रश्न को बिल्कुल नहीं पूछा जाना चाहिए। वास्तव में "संक्षिप्तता" की कीमत विवरण का "धुंधलापन" है।
जॉन्फाउंड

बेशक, जो आदमी कहता है "मैं सी में इतना अच्छा नहीं हूं" वह शुद्ध विधानसभा के गुणों की घोषणा करेगा। : D
dext0rb
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.