2011-12-12 29 views
9

मैं जीसीसी के इनलाइन असेंबलर का उपयोग कर x86 असेंबली के साथ खुद को परिचित करने की कोशिश कर रहा हूं। मैं दो नंबर (a और b) जोड़ने की कोशिश कर रहा हूं और परिणाम c में संग्रहीत कर रहा हूं। मेरे पास चार अलग-अलग प्रयास हैं, जिनमें से तीन काम करते हैं; अंतिम अपेक्षित परिणाम नहीं उत्पन्न करता है।दो संख्याओं को जोड़ना

पहले दो उदाहरण मध्यवर्ती रजिस्टर का उपयोग करते हैं, और ये दोनों ठीक काम करते हैं। तीसरे और चौथे उदाहरण इंटरमीडिएट रजिस्टर के बिना सीधे दो मानों को जोड़ने का प्रयास करते हैं, लेकिन परिणाम ऑप्टिमाइज़ेशन स्तर और उस क्रम के आधार पर भिन्न होते हैं जिसमें मैं इनपुट मान जोड़ता हूं। मुझे क्या गलत हो रहा है?

पर्यावरण है:

int a = 4; 
int b = 7; 
int c; 

उदाहरण 1::

asm(" movl %1,%%eax;" 
    " addl %2,%%eax;" 
    " movl %%eax,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    : "%eax" 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output: a=4, b=7, c=11 

उदाहरण 2:

i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3) 

पहले, चर इस प्रकार की घोषणा की जाती

asm(" movl %2,%%eax;" 
    " addl %1,%%eax;" 
    " movl %%eax,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    : "%eax" 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output: a=4, b=7, c=11 

उदाहरण 3:

asm(" movl %2,%0;" 
    " addl %1,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output with -O0: a=4, b=7, c=11 
// output with -O3: a=4, b=7, c=14 

उदाहरण 4:

// this one appears to calculate a+a instead of a+b 
asm(" movl %1,%0;" 
    " addl %2,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output with -O0: a=4, b=7, c=8 
// output with -O3: a=4, b=7, c=11 

हल किया।Matthew Slattery's answer सही है। से पहले, यह b और c दोनों के लिए eax पुन: उपयोग करने की कोशिश कर रहा था:

movl -4(%rbp), %edx 
movl -8(%rbp), %eax 
movl %edx, %eax 
addl %eax, %eax 

जगह में मैथ्यू के सुझाव दिया गया समाधान के साथ, अब ecx का उपयोग करता c अलग से पकड़ करने के लिए।

movl -4(%rbp), %edx 
movl -8(%rbp), %eax 
movl %edx, %ecx 
addl %eax, %ecx 
+2

ऑप्टिमाइज़ेशन सक्षम या बिना, मेरे लिए ठीक काम करता है। असेंबली भाषा सूची प्राप्त करने के लिए, एसएस के साथ संकलन करने का प्रयास करें। फिर आप देख सकते हैं कि कौन से रजिस्टरों का उपयोग किया जा रहा है। – TonyK

+0

बस ध्यान दिया कि मुझे अनुकूलन स्तर के आधार पर अलग-अलग परिणाम मिलते हैं। नए नमूने के साथ अद्यतन कोड नमूने। –

+0

तो असेंबली सूची आपको क्या बताती है? – TonyK

उत्तर

7

डिफ़ॉल्ट रूप से, gcc मान लेंगे कि एक इनलाइन asm ब्लॉक आउटपुट ऑपरेटरों को अपडेट करने से पहले इनपुट ऑपरेंड का उपयोग करके समाप्त हो जाएगा। इसका मतलब है कि एक इनपुट और आउटपुट दोनों एक ही रजिस्टर को आवंटित किए जा सकते हैं।

लेकिन, जरूरी है कि 4.

अपने उदाहरण 3 में मामला और जैसे नहीं है उदाहरण के लिए 3 में:

asm(" movl %2,%0;" 
    " addl %1,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    ); 

... आप पढ़ a (%1) से पहले अद्यतन किया है c (%0)। gcc दोनों %0 और %1 के लिए एक ही रजिस्टर आवंटित करने के लिए होता है, तो यह c = b; c += c की गणना करेगा, और इसलिए वास्तव में रास्ते में असफल हो जायेगी आप पर ध्यान दें: gcc बताकर

printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output with -O0: a=4, b=7, c=11 
// output with -O3: a=4, b=7, c=14 

आप इसे ठीक कर सकते हैं कि उत्पादन संकार्य हो सकता है पहले आदानों खपत होती है इस्तेमाल किया जा, इस तरह, संकार्य के लिए "&" संशोधक जोड़कर:

asm(" movl %2,%0;" 
    " addl %1,%0;" 
    : "=&r" (c) 
    : "r" (a), "r" (b) 
    ); 

(gcc डॉक्स में "Constraint Modifier Characters" देखें।)

+0

यह बिल्कुल है, धन्यवाद। फिक्स से पहले और बाद में असेंबली लिस्टिंग के साथ प्रश्न अपडेट किया गया। –

+0

इसके लिए धन्यवाद! यह ऐसा कुछ है जिसे मुझे समझने की जरूरत है, लेकिन दस्तावेज़ीकरण बल्कि मना कर रहा है। इस तरह की युक्तियाँ बहुत मूल्यवान हैं। – TonyK

0

होई, मुझे वहां कोई समस्या नहीं दिखाई दे रही है और यह संकलित और यहां ठीक काम करता है। हालांकि, एक छोटा संकेत: मैं जल्द ही नामित चर/रजिस्टरों के साथ उलझन में आया, इसलिए मैंने नामित लोगों का उपयोग करने का फैसला किया। ऐड thingy आप उदाहरण के लिए इस तरह लागू हो सकते हैं:

static inline void atomicAdd32(volInt32 *dest, int32_t source) { 
// IMPLEMENTS: add m32, r32 
__asm__ __volatile__(
     "lock; addl %[in], %[out]" 
     : [out] "+m"(*dest) 
     : [in] "ir"(source)//, "[out]" "m"(*dest) 
     ); 
return; 
    } 

(आप अभी के लिए परमाणु/लॉक बातों को अनदेखा कर सकते), कि बनाता है स्पष्ट क्या होता है:

1) क्या रजिस्टरों लिखने योग्य, पढ़े जाने योग्य हैं या

2) क्या उपयोग किया जाता है (मेमोरी, रजिस्ट्रार), जो प्रदर्शन और घड़ी चक्रों की बात आती है, क्योंकि पंजीकरण संचालन स्मृति तक पहुंचने वालों की तुलना में तेज़ होते हैं।

चीयर्स, जी

पी.एस .: आप जांच की है कि क्या आपके संकलक कोड rearranges?

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