दिलचस्प पोस्ट
AngularJS में गुंजाइश प्रोटोटाइप / प्रोटोटाइपिकल विरासत की बारीकियों क्या हैं? मैं टेक्स्ट बॉक्स में कैरेट के (एक्स, वाई) पिक्सेल निर्देशांक कैसे प्राप्त करूं? LINQ के साथ आप "नॉट इन" क्वेरी कैसे करेंगे? कुंजी / मान जावास्क्रिप्ट ऑब्जेक्ट की कुंजी पाने का सर्वोत्तम तरीका जावास्क्रिप्ट कुंजीकोड बनाम चारकोडा एंड्रॉइड चालू / बंद वाईफाई हॉटस्पॉट प्रोग्रामेटिक रूप से एंड्रॉइड और एक्सएमपीपी: वर्तमान में उपलब्ध समाधान पायथन: मैं अजैथ फ़ंक्शन को समानांतर में कैसे चला सकता हूँ? मेरे DatePickerFragment से प्रारूपित दिनांक स्ट्रिंग कैसे स्थानांतरित करें? एंड्रॉइड "केवल एक मूल धागा जो दृश्य पदानुक्रम बनाता है, उसके विचारों को छू सकता है।" मैं सीएसएस के साथ पाठ कैसे बदल सकता हूँ? JTable में समूह को JRadioButton जोड़ने के लिए कैसे Gradle का उपयोग कर एक रिलीज एपीके फाइल बनाने के लिए कैसे? एक यूआरएल से विंडोज बैच फ़ाइल फाइल डाउनलोड करें मैं jQuery में पृष्ठभूमि छवि आकार कैसे प्राप्त करूं?

'__asm' और '__asm__' के बीच अंतर क्या है?

मैं सी में इनलाइन विधानसभा सीख रहा हूं जहाँ तक मैं बता सकता हूं, __asm { ... }; बीच का अंतर __asm { ... }; और __asm__("..."); यह है कि पहले mov eax, var और दूसरे का उपयोग movl %0, %%eax साथ :"=r" (var) अंत में :"=r" (var) करता है। इसके अलावा, पहले के बारे में बहुत कम वेबसाइटें हैं क्या अन्य मतभेद हैं?

वेब के समाधान से एकत्रित समाधान "'__asm' और '__asm__' के बीच अंतर क्या है?"

आप का उपयोग कौन सा आपके कंपाइलर पर निर्भर करता है। यह सी भाषा की तरह मानक नहीं है

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

यदि आप प्रदर्शन कारणों के लिए इनलाइन एएसएम का उपयोग कर रहे हैं, तो यह एमएसवीसी इनलाइन एएसएम केवल व्यवहार्य बनाता है यदि आप पूरी तरह से एएसएम में पूरी तरह से लूप लिखते हैं, इनलाइन फ़ंक्शन में लघु अनुक्रम लपेटने के लिए नहीं। नीचे दिए गए उदाहरण (फ़ंक्शन के साथ idiv लपेटने) एक तरह की चीज है जो idiv खराब है: ~ 8 अतिरिक्त स्टोर / लोड निर्देश

एमएसवीसी इनलाइन एएसएम (एमएसवीसी द्वारा इस्तेमाल किया जाता है और शायद आईसीसी, शायद कुछ वाणिज्यिक कंपलर्स में भी उपलब्ध है):

  • आपके एएसएम को यह पता लगाने के लिए कि आपके कोड चरण किस पर रजिस्टरों को पंजीकृत करता है
  • केवल मेमोरी के माध्यम से डेटा स्थानांतरित कर सकता है रजिस्ट्रार में रहते हुए डेटा को संकलक द्वारा आपके mov ecx, shift_count लिए तैयार किया mov ecx, shift_count , उदाहरण के लिए। इसलिए एकल एएसएम अनुदेश का उपयोग करना जो आपके लिए कंपाइलर उत्पन्न नहीं करेगा, उसमें मेमोरी के माध्यम से रास्ते में और बाहर रास्ते पर एक गोल ट्रिप शामिल है।
  • अधिक शुरुआत के अनुकूल, लेकिन अकसर इसके अलावा डेटा प्राप्त करने से बचने में अक्सर असंभव होता है वाक्यविन्यास सीमाओं के अलावा, एमएसवीसी के मौजूदा संस्करणों में ऑप्टिमाइज़र इनलाइन एएसएम ब्लॉकों के अनुकूलन के लिए अच्छा नहीं है, या तो

जीएनयू सी इनलाइन एएसएम एएसएम सीखने का एक अच्छा तरीका नहीं है आपको एएसएम बहुत अच्छी तरह से समझना है ताकि आप अपने कोड के बारे में कंपाइलर को बता सकें। और आपको समझना होगा कि कम्पाइलर को क्या जानना चाहिए। उस उत्तर में अन्य इनलाइन एएसएम गाइड और क्यू एंड ए के रूप में लिंक भी है। एक्स 86 टैग विकी में एएसएम के लिए सामान्य रूप से बहुत अच्छी चीजें हैं, लेकिन जीएनयू इनलाइन एएसएम के लिए इसके लिए लिंक है (उस उत्तर में सामान गैर-एक्स 86 प्लेटफार्मों पर जीएनयू इनलाइन एएसएम पर भी लागू होता है।)

जीएनयू सी इनलाइन एएसएम सिंटैक्स जीसीसी, क्लैग, आईसीसी, और शायद कुछ वाणिज्यिक कंपलर जो जीएनयू सी को लागू करते हैं द्वारा उपयोग किया जाता है:

  • आपको कम्पाइलर को बताने की ज़रूरत है कि आप कितनी बार ऐसा करने में विफलता आसपास के कोड के टूटने को गैर-स्पष्ट हार्ड-टू-डिबग के तरीकों से प्रेरित करेगा।
  • कम्पाइलर को इनपुट की आपूर्ति कैसे करें, और आउटपुट कैसे प्राप्त करें, यह बताकर सिंटैक्स को पढ़ने, सीखने, और उपयोग करने के लिए शक्तिशाली लेकिन मुश्किल। उदाहरण के लिए "c" (shift_count) संकलक को आपके इनलाइन एएसएम रन से पहले ecx को shift_count चर में डाल दिया जाएगा।
  • कोड के बड़े ब्लॉकों के लिए अतिरिक्त क्लैन्की, क्योंकि एएसएम को स्ट्रिंग स्थिरता के अंदर होना चाहिए तो आप आमतौर पर जरूरत है
     "insn% [inputvar], %% reg \ n \ t" // टिप्पणी
     "insn2 %% reg,% [outputvar] \ n \ t"
  • बहुत माफ़ी / कठिन है, लेकिन निचला ऊपरी इलाका esp को अनुमति देता है। एकल निर्देश लपेटने के लिए (एक निर्देश लपेटकर मूल डिज़ाइन इरादा था, यही कारण है कि यदि आपको एक समस्या है, तो आपको इनपुट और आउटपुट के लिए उसी रजिस्टर का इस्तेमाल करने से रोकने के लिए प्रारंभिक क्लाबर्स के बारे में विशेष रूप से कंपाइलर को बता देना होगा।)

उदाहरण: पूर्ण-चौड़ाई पूर्णांक विभाजन ( div )

एक 32 बिट सीपीयू पर, 32bit पूर्णांक द्वारा एक 64 बिट पूर्णांक को विभाजित करना, या एक पूर्ण-गुणा (32×32-> 64) करना, इनलाइन asm से लाभ हो सकता है जीसीसी और idiv (int64_t)a / (int32_t)b लिए (int64_t)a / (int32_t)b लाभ नहीं लेते, संभवतः क्योंकि निर्देश दोष अगर परिणाम 32bit रजिस्टर में फिट नहीं है। इसलिए एक डिवि से अंशांकन और शेष होने के बारे में इस क्यू एंड ए के विपरीत, इनलाइन एएसएम के लिए यह उपयोग-केस है। (जब तक कम्पाइलर को सूचित करने का कोई तरीका नहीं है कि परिणाम ठीक हो जाए, तो मूंछें गलती न करें।)

हम फोन करने वाले सम्मेलनों का उपयोग करेंगे जो रजिस्टरों में कुछ आर्गियां डालते हैं (साथ hi सही रजिस्टर में भी), ऐसी स्थिति को दिखाने के लिए जो इस तरह के एक छोटे फ़ंक्शन को इनलाइन करते समय आप देख रहे हैं के करीब है।


MSVC

इनलाइन एएसएम का उपयोग करते समय रजिस्टर-एआरजी कॉल सम्मेलनों के साथ सावधान रहें जाहिरा तौर पर इनलाइन एएसएम समर्थन इतनी बुरी तरह से डिज़ाइन / कार्यान्वित किया जाता है कि कंपाइलर इनलाइन एएसएम के चारों ओर आरजीआर रजिस्टरों को सहेज / आरक्षित नहीं कर सकता है, यदि इन एल्ग्स को इनलाइन एएसएम में इस्तेमाल नहीं किया गया है । धन्यवाद @ रोरस्रिज इस ओर इशारा करते हुए।

 // MSVC. Be careful with _vectorcall & inline-asm: see above // we could return a struct, but that would complicate things int _vectorcall div64(int hi, int lo, int divisor, int *premainder) { int quotient, tmp; __asm { mov edx, hi; mov eax, lo; idiv divisor mov quotient, eax mov tmp, edx; // mov ecx, premainder // Or this I guess? // mov [ecx], edx } *premainder = tmp; return quotient; } 

रिक्सेस्टर पर एमएसवीसी 19.00.23026 /O2 साथ संकलित (एक main() साथ जो एक्सई की निर्देशिका पाता है और कंपाइलर के एसएसएम आउटपुट को स्टडआउट में डंप करता है )।

 ## My added comments use. ## ## ... define some symbolic constants for stack offsets of parameters ; 48 : int ABI div64(int hi, int lo, int divisor, int *premainder) { sub esp, 16 ; 00000010H mov DWORD PTR _lo$[esp+16], edx ## these symbolic constants match up with the names of the stack args and locals mov DWORD PTR _hi$[esp+16], ecx ## start of __asm { mov edx, DWORD PTR _hi$[esp+16] mov eax, DWORD PTR _lo$[esp+16] idiv DWORD PTR _divisor$[esp+12] mov DWORD PTR _quotient$[esp+16], eax ## store to a local temporary, not *premainder mov DWORD PTR _tmp$[esp+16], edx ## end of __asm block mov ecx, DWORD PTR _premainder$[esp+12] mov eax, DWORD PTR _tmp$[esp+16] mov DWORD PTR [ecx], eax ## I guess we should have done this inside the inline asm so this would suck slightly less mov eax, DWORD PTR _quotient$[esp+16] ## but this one is unavoidable add esp, 16 ; 00000010H ret 8 

अतिरिक्त मोल निर्देशों का एक टन है, और कंपाइलर इसके किसी भी हिस्से को अनुकूलित करने के करीब नहीं आ रहा है। मैंने सोचा था कि यह इनलाइन एएसएम के अंदर mov tmp, edx को देख और समझ mov tmp, edx , और एक स्टोर को premainder लिए बना premainder । लेकिन इससे पहले कि स्टेक से premainder लोड करने की आवश्यकता होती है, इनलाइन एएसएम ब्लॉक से पहले एक रजिस्टर में, मुझे लगता है

यह फ़ंक्शन वास्तव में सामान्य चीज़ों के साथ-साथ-स्टैक ABI के साथ _vectorcall से भी बदतर है । रजिस्टरों में दो इनपुट के साथ, यह उन्हें स्मृति में संग्रहीत करता है ताकि इनलाइन एएसएम उन्हें नामित वैरिएबल से लोड कर सके। यदि इन्हें रेखांकित किया गया है, तो पैरामीटर का और भी अधिक संभवतः रेग में हो सकता है, और उन्हें उन सब को स्टोर करना होगा, ताकि एएसएम में मैमोरी ऑपरैन्ड होंगे! इसलिए जीसीसी के विपरीत, हमें इसे इनलाइन करने से बहुत लाभ नहीं मिलता।

एएसएम ब्लॉक के अंदर *premainder = tmp करना अधिक एएसएम में लिखे गए कोड का मतलब है, लेकिन शेष के लिए पूरी तरह से ब्रेइंडेड स्टोर / लोड / स्टोअर पथ से बचता है। इससे अनुक्रम की गणना 2 कुल, नीचे से 11 तक हो जाती है ( ret सहित नहीं)।

मैं एमएसवीसी से बाहर का सबसे अच्छा संभव कोड प्राप्त करने की कोशिश कर रहा हूं, "इसे गलत उपयोग नहीं" और एक पुआल-पुरुष तर्क बनाने के लिए। लेकिन AFAICT बहुत कम दृश्य लपेटने के लिए यह भयानक है। संभवतः 64/32 -> 32 डिवीजन के लिए एक आंतरिक फ़ंक्शन है, जो कि कंपाइलर को इस विशेष मामले के लिए अच्छा कोड उत्पन्न करने की अनुमति देता है, इसलिए एमएसवीसी पर इनलाइन एएसएम का उपयोग करने का पूरा आधार एक स्ट्रॉ-मैन तर्क हो सकता है


जीएनयू सी (जीसीसी / क्लैंक / आईसीसी)

जीसीसी डीवी 64 को इनलाइन करने पर यहां दिखाए गए आउटपुट के मुकाबले बेहतर है, क्योंकि यह आमतौर पर पूर्ववर्ती कोड की व्यवस्था करता है ताकि पहली जगह में ईडीएक्स: ईएक्स में 64 बिट पूर्णांक उत्पन्न किया जा सके।

मैं 32 बिट vectorcall ABI के लिए संकलक के लिए जीसीसी प्राप्त नहीं कर सकता नाराज़, लेकिन यह इनलाइन एएसएम पर बेकार हो सकता है (इसे गोदाम लिंक पर आज़माएं: यह मेमोरी के माध्यम से फ़ंक्शन एब बाउंस करता है) 64 बिट एमएस कॉलिंग सम्मेलन 32 बिट वेक्टरकॉल के करीब है, जिसमें एडएक्स के पहले दो पैरामिक्स, एक्सीक्स हैं। यह अंतर यह है कि स्टैक्स का उपयोग करने से पहले 2 और पैराग्राफ रेग में जाते हैं (और यह कि कैली स्टैक्स से आर्ग्स पॉप नहीं करता है, जो कि एमएसवीसी आउटपुट में ret 8 बारे में था।)

 // GNU C // change everything to int64_t to do 128b/64b -> 64b division // MSVC doesn't do x86-64 inline asm, so we'll use 32bit to be comparable int div64(int lo, int hi, int *premainder, int divisor) { int quotient, rem; asm ("idivl %[divsrc]" : "=a" (quotient), "=d" (rem) // a means eax, d means edx : "d" (hi), "a" (lo), [divsrc] "rm" (divisor) // Could have just used %0 instead of naming divsrc // note the "rm" to allow the src to be in a register or not, whatever gcc chooses. // "rmi" would also allow an immediate, but unlike adc, idiv doesn't have an immediate form : // no clobbers ); *premainder = rem; return quotient; } 

gcc -m64 -O3 -mabi=ms -fverbose-asm साथ संकलित -32 के साथ आपको 3 भार, मूव, और एक स्टोर मिलता है, क्योंकि आप उस दैवीय लिंक में सामान बदलने से देख सकते हैं।

  mov eax, ecx # lo, lo idivl r9d # divisor mov DWORD PTR [r8], edx # *premainder_7(D), rem ret 

32 बिट वेक्टरकॉल के लिए, जीसीसी कुछ ऐसा करना होगा

  ## Not real compiler output, but probably similar to what you'd get mov eax, ecx # lo, lo mov ecx, [esp+12] # premainder idivl [esp+16] # divisor mov DWORD PTR [ecx], edx # *premainder_7(D), rem ret 8 

एमएसवीसी जीसीसी के 4 के मुकाबले 13 निर्देश (रिट सहित नहीं) का उपयोग करता है। जैसा कि मैंने कहा था, इनलाइनिंग के साथ, यह संभावित रूप से सिर्फ एक ही है, जबकि एमएसवीसी अभी भी 9 का उपयोग करेगा। (यह स्टैक स्पेस या लोड आरक्षित करने की आवश्यकता नहीं होगी premainder ; मैं मान रहा हूँ कि यह अभी भी 3 में से 2 इनपुट के बारे में स्टोर करने के लिए है। फिर यह एएसएम के अंदर उन्हें पुनः लोड करता है, idiv चलाता है, दो आउटपुट स्टोर करता है और एएसएम के बाहर उन्हें पुनः लोड करता है, इसलिए इनपुट के लिए 4 लोड / स्टोर्स आउटपुट के लिए एक और 4।)

जीसीसी कंपाइलर के साथ, यह एक बड़ा अंतर नहीं है। asm या __asm या __asm__ एक ही हैं, वे सिर्फ संघर्ष नाम स्थान उद्देश्य से बचने के लिए उपयोग करते हैं (वहाँ उपयोगकर्ता परिभाषित कार्य है कि नाम asm, आदि)