थोड़ा ऑफ-विषय लेकिन मैं जीसीसी इनलाइन असेंबली पर थोड़ा सा अनुसरण करना चाहता हूं।
(गैर-) __volatile__
की आवश्यकता इस तथ्य से आती है कि जीसीसी इनलाइन असेंबली को अनुकूलित करता है। जीसीसी साइड इफेक्ट्स/पूर्वापेक्षाएँ के लिए असेंबली स्टेटमेंट का निरीक्षण करता है, और यदि उन्हें पता चलता है कि यह अस्तित्व में नहीं है तो यह असेंबली निर्देश को स्थानांतरित करने या को को हटाने का निर्णय ले सकता है। सभी __volatile__
संकलक को बताना है "देखभाल करना बंद करें और इसे वहां रखें"।
जो आमतौर पर आप वास्तव में नहीं चाहते हैं।
यह वह जगह है जहां बाधाओं में आते हैं के लिए की जरूरत नाम ओवरलोड हो गया है और वास्तव में जीसीसी इनलाइन विधानसभा में अलग अलग चीजों के लिए इस्तेमाल किया:।
- बाधाओं
asm()
ब्लॉक में इस्तेमाल किया इनपुट/आउटपुट ऑपरेंड निर्दिष्ट
- बाधाएं "क्लॉबर सूची" निर्दिष्ट करती हैं, जो बताती है कि "राज्य" (रजिस्टर्स, हालत कोड, मेमोरी)
asm()
से प्रभावित होते हैं।
- की कमी (, रजिस्टर, पते, ऑफसेट, स्थिरांक ...) ऑपरेंड के वर्गों को निर्दिष्ट
- बाधाओं संघों/कोडांतरक संस्थाओं और C/C++ चर के बीच बाइंडिंग/भाव
कई मामलों में, डेवलपर्स की घोषणा दुरुपयोग__volatile__
क्योंकि उन्होंने देखा कि उनके कोड को या तो चारों ओर ले जाया जा रहा है या इसके बिना गायब हो रहा है। यदि ऐसा होता है, तो आमतौर पर यह एक संकेत है कि डेवलपर ने का प्रयास नहीं किया है ताकि जीसीसी को साइड इफेक्ट्स/असेंबली के पूर्वापेक्षाएँ के बारे में बताया जा सके। उदाहरण के लिए, इस गाड़ी कोड:
register int foo __asm__("rax") = 1234;
register int bar __adm__("rbx") = 4321;
asm("add %rax, %rbx");
printf("I'm expecting 'bar' to be 5555 it is: %d\n", bar);
यह कई कीड़े मिला है: (!)
- एक के लिए, यह केवल संकलित एक जीसीसी बग के कारण। आम तौर पर, इनलाइन असेंबली में रजिस्टर नाम लिखने के लिए, डबल
%%
की आवश्यकता होती है, लेकिन उपरोक्त में यदि आप वास्तव में उन्हें निर्दिष्ट करते हैं तो आपको एक कंपाइलर/असेंबलर त्रुटि मिलती है, /tmp/ccYPmr3g.s:22: Error: bad register name '%%rax'
।
- दूसरा, यह कंपाइलर को नहीं कह रहा है कि आपको कहां और कहाँ चर की आवश्यकता है। इसके बजाए, यह मानता है संकलक सम्मान
asm()
सचमुच। यह माइक्रोसॉफ्ट विजुअल सी ++ के लिए सच हो सकता है लेकिन जीसीसी के लिए मामले नहीं है।
आप इसे संकलन हैं अनुकूलन के बिना, यह बनाता है:
0000000000400524 <main>:
[ ... ]
400534: b8 d2 04 00 00 mov $0x4d2,%eax
400539: bb e1 10 00 00 mov $0x10e1,%ebx
40053e: 48 01 c3 add %rax,%rbx
400541: 48 89 da mov %rbx,%rdx
400544: b8 5c 06 40 00 mov $0x40065c,%eax
400549: 48 89 d6 mov %rdx,%rsi
40054c: 48 89 c7 mov %rax,%rdi
40054f: b8 00 00 00 00 mov $0x0,%eax
400554: e8 d7 fe ff ff callq 400430 <[email protected]>
[...]
आप अपने
add
अनुदेश पा सकते हैं, और दो रजिस्टरों की initializations, और यह उम्मीद प्रिंट होगा। यदि, दूसरी ओर, आप अनुकूलन को क्रैंक करते हैं, तो कुछ और होता है:
0000000000400530 <main>:
400530: 48 83 ec 08 sub $0x8,%rsp
400534: 48 01 c3 add %rax,%rbx
400537: be e1 10 00 00 mov $0x10e1,%esi
40053c: bf 3c 06 40 00 mov $0x40063c,%edi
400541: 31 c0 xor %eax,%eax
400543: e8 e8 fe ff ff callq 400430 <[email protected]>
[ ... ]
"उपयोग" रजिस्टरों दोनों की आपकी प्रारंभिकता अब वहां नहीं है।कंपाइलर ने उन्हें त्याग दिया क्योंकि ऐसा कुछ भी नहीं देख सकता था, और जब इसे असेंबली निर्देश रखा गया था, तो इसे
दो चर के किसी भी उपयोग से पहले रखा गया। यह वहां है लेकिन यह कुछ भी नहीं करता है (सौभाग्य से वास्तव में ... यदि
rax
/
rbx
उपयोग में किया गया था जो बता सकता है कि क्या हुआ होगा ...)।
और इसका कारण यह है कि आपने वास्तव में जीसीसी को बताया कि असेंबली इन रजिस्टरों/इन ऑपरेंड मानों का उपयोग कर रही है। इसमें volatile
के साथ कुछ भी नहीं है, लेकिन इस तथ्य के साथ आप एक बाधा मुक्त asm()
अभिव्यक्ति का उपयोग कर रहे हैं।
तरीका यह सही ढंग से बाधाओं के माध्यम से है ऐसा करने के लिए, यानी आप का उपयोग करेंगे:
int foo = 1234;
int bar = 4321;
asm("add %1, %0" : "+r"(bar) : "r"(foo));
printf("I'm expecting 'bar' to be 5555 it is: %d\n", bar);
इस संकलक बताता है कि विधानसभा:
- एक रजिस्टर में एक तर्क है,
"+r"(...)
कि दोनों को असेंबली कथन से पहले प्रारंभ करने की आवश्यकता है, और असेंबली कथन द्वारा संशोधित किया गया है, और इसके साथ परिवर्तनीय bar
को संबद्ध करें।
- में एक रजिस्टर में दूसरा तर्क है,
"r"(...)
जिसे असेंबली स्टेटमेंट से पहले शुरू किया जाना चाहिए और कथन द्वारा संशोधित/संशोधित नहीं किया गया है। यहां, इसके साथ foo
संबद्ध करें।
नोटिस कोई पंजीकरण असाइनमेंट निर्दिष्ट नहीं है - संकलक चुनता है कि संकलन के चर/राज्य के आधार पर।उपरोक्त के (अनुकूलित) आउटपुट:
0000000000400530 <main>:
400530: 48 83 ec 08 sub $0x8,%rsp
400534: b8 d2 04 00 00 mov $0x4d2,%eax
400539: be e1 10 00 00 mov $0x10e1,%esi
40053e: bf 4c 06 40 00 mov $0x40064c,%edi
400543: 01 c6 add %eax,%esi
400545: 31 c0 xor %eax,%eax
400547: e8 e4 fe ff ff callq 400430 <[email protected]>
[ ... ]
जीसीसी इनलाइन असेंबली बाधाएं
लगभग किसी भी रूप में या अन्य में लगभग हमेशा आवश्यक हैं, लेकिन संकलक को समान आवश्यकताओं का वर्णन करने के कई संभावित तरीके हो सकते हैं; इसके बाद के संस्करण के बजाय, आप भी लिख सकते हैं:
asm("add %1, %0" : "=r"(bar) : "r"(foo), "0"(bar));
यह बताता है जीसीसी:
- बयान एक निर्गम संकार्य, चर
bar
, कि बयान के बाद, "=r"(...)
एक रजिस्टर में पाया जाएगा है
- बयान एक इनपुट संकार्य, चर
foo
है, जो एक रजिस्टर में रखा जा रहा है, है "r"(...)
- संकार्य शून्य भी एक इनपुट संकार्य है औरके साथ प्रारंभ करने के लिए
या, फिर से एक विकल्प:
asm("add %1, %0" : "+r"(bar) : "g"(foo));
जो बताता है जीसीसी:
- bla (जम्हाई - पहले की तरह ही,
bar
दोनों इनपुट/आउटपुट)
- कथन में एक इनपुट ऑपरेंड है, वेरिएबल
foo
, जो कथन परवाह नहीं करता है कि यह एक regis में है या नहीं टेर, स्मृति या एक संकलन समय निरंतर में
परिणाम पूर्व से अलग है (कि "g"(...)
बाधा है):
0000000000400530 <main>:
400530: 48 83 ec 08 sub $0x8,%rsp
400534: bf 4c 06 40 00 mov $0x40064c,%edi
400539: 31 c0 xor %eax,%eax
40053b: be e1 10 00 00 mov $0x10e1,%esi
400540: 81 c6 d2 04 00 00 add $0x4d2,%esi
400546: e8 e5 fe ff ff callq 400430 <[email protected]>
[ ... ]
क्योंकि अब, जीसीसी
वास्तव में पता लगा है
foo
एक संकलन समय स्थिर है और बस
add
निर्देश में मान को एम्बेड किया गया है! क्या वह साफ नहीं है?
मान्य है, यह जटिल है और इसका उपयोग करने में लग रहा है। लाभ यह है कि कंपाइलर को चुनने दें जो कि ऑपरेटरों को समग्र रूप से कोड को अनुकूलित करने की अनुमति देता है; यदि, उदाहरण के लिए, एक इनलाइन असेंबली कथन का उपयोग मैक्रो और/या static inline
फ़ंक्शन में किया जाता है, तो कॉलर संदर्भ कॉलिंग संदर्भ के आधार पर, कोड के विभिन्न तत्कालताओं पर विभिन्न रजिस्टरों का चयन कर सकते हैं। या यदि कोई निश्चित मान एक स्थान पर संकलित-समय मूल्यांकन/स्थिर है लेकिन दूसरे में नहीं है, तो संकलक इसके लिए बनाई गई असेंबली को तैयार कर सकता है।
जीसीसी इनलाइन असेंबली बाधाओं के बारे में सोचें "विस्तारित फ़ंक्शन प्रोटोटाइप" के रूप में - वे संकलक को बताते हैं कि तर्क/वापसी मूल्यों के लिए किस प्रकार और स्थान हैं, साथ ही कुछ और भी। यदि आप इन बाधाओं को निर्दिष्ट नहीं करते हैं, तो आपकी इनलाइन असेंबली उन कार्यों के एनालॉग का निर्माण कर रही है जो वैश्विक चर/राज्य पर ही काम करती हैं - जो कि हम शायद सभी सहमत हैं, शायद ही कभी आप जो भी चाहते हैं वह कर रहे हैं।
जीडीबी के साथ कोड के माध्यम से कदम क्यों नहीं उठाएं ताकि आप देख सकें कि * क्या हो रहा है? –