c - x86 कॉलिंग कन्वेंशन: क्या स्टैक द्वारा दिए गए तर्क केवल पढ़ने के लिए होंगे?




stack argument-passing (2)

ऐसा लगता है कि राज्य के अत्याधुनिक संकलक का प्रयोग केवल-पढ़ने के लिए स्टैक द्वारा पारित तर्कों का होता है ध्यान दें कि x86 कॉलिंग सम्मेलन में, कॉलर स्टैक पर आर्गुमेंट्स को धक्का देता है और कैली स्टैक में तर्क का उपयोग करता है। उदाहरण के लिए, निम्न सी कोड:

extern int goo(int *x);
int foo(int x, int y) {
  goo(&x);
  return x;
}

ओएस एक्स 10.10 में clang -O3 -c gc -S -m32 में संकलित किया गया है:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 10
    .globl  _foo
    .align  4, 0x90
_foo:                                   ## @foo
## BB#0:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    8(%ebp), %eax
    movl    %eax, -4(%ebp)
    leal    -4(%ebp), %eax
    movl    %eax, (%esp)
    calll   _goo
    movl    -4(%ebp), %eax
    addl    $8, %esp
    popl    %ebp
    retl


.subsections_via_symbols

यहां, पैरामीटर x ( 8(%ebp) ) पहले %eax में लोड किया गया है; और फिर -4(%ebp) में संग्रहीत; और पता -4(%ebp) %eax में संग्रहीत है; और फ़ंक्शन goo को %eax पास किया जाता है

मुझे आश्चर्य है कि क्यों नाराज़ कोड उत्पन्न करता है जो 8(%ebp) से -4(%ebp) में संग्रहीत मूल्य की प्रतिलिपि बनाता है, बजाय फ़ंक्शन goo को पता 8(%ebp) करने के बजाय यह स्मृति संचालन को बचाएगा और परिणामस्वरूप एक बेहतर प्रदर्शन होगा। मैंने जीसीसी में एक समान व्यवहार (ओएस एक्स के तहत) देखा। अधिक विशिष्ट होने के लिए, मुझे आश्चर्य है कि कंपलर क्यों नहीं उत्पन्न करते हैं:

  .section  __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 10
    .globl  _foo
    .align  4, 0x90
_foo:                                   ## @foo
## BB#0:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    leal    8(%ebp), %eax
    movl    %eax, (%esp)
    calll   _goo
    movl    8(%ebp), %eax
    addl    $8, %esp
    popl    %ebp
    retl


.subsections_via_symbols

मैं दस्तावेजों की खोज करता हूं यदि x86 कॉलिंग कॉन्फ़्रेंस पारित किए गए तर्कों को केवल-पढ़ने के लिए मांग करता है, लेकिन मुझे इस मुद्दे पर कुछ भी नहीं मिला। क्या किसी को इस मुद्दे पर कोई सोचा है?


दरअसल, मैंने जीसीसी का उपयोग करते हुए इस फ़ंक्शन को संकलित किया:

int foo(int x)
{
    goo(&x);
    return x;
}

और यह इस कोड को उत्पन्न करता है:

_foo:
        pushl       %ebp
        movl        %esp, %ebp
        subl        $24, %esp
        leal        8(%ebp), %eax
        movl        %eax, (%esp)
        call        _goo
        movl        8(%ebp), %eax
        leave
        ret

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


सी के लिए नियम यह है कि पैरामीटर मूल्य से पारित किया जाना चाहिए। एक कंपाइलर एक भाषा (नियमों के एक सेट के साथ) को एक अलग भाषा में परिवर्तित करता है (संभवत: अलग-अलग नियमों के साथ)। केवल सीमा यह है कि व्यवहार एक ही रहता है सी भाषा के नियम लक्ष्य भाषा (उदाहरण के विधानसभा) पर लागू नहीं होते हैं

इसका क्या मतलब यह है कि यदि एक संकलक विधानसभा भाषा पैदा करने जैसा लगता है जहां पैरामीटर संदर्भ से पारित होते हैं और मूल्य से पारित नहीं होते हैं; तो यह पूरी तरह से कानूनी है (जब तक व्यवहार उसी वही रहता है)।

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

आप अपनी खुद की एबीआई का आविष्कार भी कर सकते हैं जो अलग-अलग है (और अपने खुद के औजारों को लागू करें जो आपकी खुद की अलग-अलग एबीआई का समर्थन करते हैं) और सी मानक मानकों के रूप में पूरी तरह से कानूनी है; भले ही आपकी एबीआई को सब कुछ के लिए "संदर्भ से गुजारें" की आवश्यकता हो, (जब तक कि व्यवहार समान रहता है)।