2010-07-09 18 views
10

निर्देशों और सी कार्यक्रमों को इकट्ठा करने में कुछ पृष्ठभूमि के साथ, मैं कल्पना कर सकता हूं कि एक संकलित फ़ंक्शन कैसा दिखता है, लेकिन यह मजाकिया है कि मैंने कभी भी इतनी सावधानी से सोचा नहीं है कि संकलित सी ++ वर्ग कैसा दिखता है।संकलित सी ++ वर्ग कैसा दिखता है?

bash$ cat class.cpp 
#include<iostream> 
class Base 
{ 
    int i; 
    float f; 
}; 

bash$ g++ -c class.cpp 

मैं भाग गया:

bash$objdump -d class.o 
bash$readelf -a class.o 

लेकिन मुझे समझने के लिए कि मैं क्या मिल मुश्किल है।

क्या कोई मुझे बता सकता है या कुछ अच्छे शुरुआती बिंदु सुझा सकता है।

+1

यह सी संरचना के समान ही दिखाई देगा। –

+0

सही! इसलिए इससे मुझे लगता है कि संरचनाओं को कैसे संकलित किया जाएगा, और मुझे एहसास हुआ कि मैं शायद इस भाग को समझने के लिए नहीं समझूंगा। bash $ cat struct.cpp संरचना परीक्षण { int i; फ्लोट एफ; }; इस फ़ाइल के अनुरूप फ़ाइल को क्या ऑब्जेक्ट करना चाहिए और क्या होगा? मैं समझता हूं, संरचनाओं से संबंधित फ़ाइलों को ऑब्जेक्ट इस तरह के कार्यों की तरह नहीं लगेगा कि कोई असेंबली निर्देश नहीं हैं। धन्यवाद, – xyz

+0

विशेष रूप से, इस struct.cpp में ऑब्जेक्ट फ़ाइलों में कोई टेक्स्ट और न ही डेटा अनुभाग होना चाहिए? मुझे नहीं पता, अगर यह सवाल हालांकि एल्फ फाइलों के प्रारूप की ओर झुक रहा है। – xyz

उत्तर

0

प्रयास करें

जी ++ एस class.cpp

है कि आप एक विधानसभा फ़ाइल 'class.s' (पाठ फ़ाइल) जो आप एक पाठ संपादक के साथ पढ़ सकते हैं दे देंगे। हालांकि, आपका कोड कुछ भी नहीं करता है (कक्षा घोषित करने से कोड उत्पन्न नहीं होता है) ताकि आपके पास असेंबली फ़ाइल में अधिक न हो।

2

ठीक है। संकलित कक्षाओं के साथ कुछ खास नहीं है। संकलित कक्षाएं भी मौजूद नहीं हैं। क्या अस्तित्व है जो वस्तुओं के बीच संभावित पैडिंग के साथ मेमोरी के फ्लैट हिस्से हैं? और कोड में कहीं भी स्टैंडअलोन सदस्य फ़ंक्शंस जो किसी ऑब्जेक्ट को पॉइंटर को पहले पैरामीटर के रूप में लेते हैं। मैं (* base_address + sizeof (int)): च

यह क्षेत्रों के बीच paddings करना संभव है

तो वर्ग बेस का उद्देश्य कुछ

(* base_address) होना चाहिए? लेकिन वह हार्डवेयर विशिष्ट है। प्रोसेसर मेमोरी मॉडल के आधार पर।

भी ... डीबग संस्करण में डीबग प्रतीकों में कक्षा विवरण पकड़ना संभव है। लेकिन वह संकलक विशिष्ट है। आपको ऐसे प्रोग्राम की खोज करनी चाहिए जो आपके कंपाइलर के लिए डीबग प्रतीकों को डंप करे।

2

"संकलित कक्षाएं" का अर्थ "संकलित विधियों" है।

एक विधि एक अतिरिक्त पैरामीटर के साथ एक सामान्य कार्य है, आमतौर पर एक रजिस्टर में डाल दिया जाता है (ज्यादातर% ecx मुझे विश्वास है, यह ज्यादातर विंडोज कंप्यूटर्स के लिए कम से कम सच है, जिन्हें __thiscall सम्मेलन का उपयोग करके COM ऑब्जेक्ट्स का उत्पादन करना पड़ता है)।

तो सी ++ कक्षाएं सामान्य कार्यों के समूह से बहुत अलग नहीं हैं, नाम उलझन और vtables की स्थापना के लिए रचनाकारों/विनाशकों में कुछ जादू को छोड़कर।

19

कक्षाएं (अधिक या कम) नियमित structs के रूप में बनाई गई हैं। विधियां (अधिक या कम ...) फ़ंक्शंस में परिवर्तित होती हैं जो पहला पैरामीटर "यह" होता है। कक्षा चर के संदर्भ ऑफ़सेट के रूप में "इस" के रूप में किए जाते हैं।

विरासत तक, सी ++ एफएक्यू लाइट से उद्धरण दें, जो http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.4 पर प्रतिबिंबित है। यह अध्याय दिखाता है कि आभासी कार्यों असली हार्डवेयर में कहा जाता है (क्या करता संकलन मशीन कोड में बनाने


एक उदाहरण काम करते हैं मान लीजिए वर्ग बेस 5 आभासी कार्य करता है:।। virt0()virt4() के माध्यम से।

// Your original C++ source code 
class Base { 
public: 
    virtual arbitrary_return_type virt0(...arbitrary params...); 
    virtual arbitrary_return_type virt1(...arbitrary params...); 
    virtual arbitrary_return_type virt2(...arbitrary params...); 
    virtual arbitrary_return_type virt3(...arbitrary params...); 
    virtual arbitrary_return_type virt4(...arbitrary params...); 
    ... 
}; 

चरण # 1: संकलक एक स्थिर तालिका 5 समारोह-संकेत युक्त बनाता है, स्थिर स्मृति में उस तालिका कहीं दफन। कई (सभी नहीं) compilers .cpp संकलित करते समय इस तालिका को परिभाषित करते हैं जो बेस के पहले गैर-इनलाइन वर्चुअल फ़ंक्शन को परिभाषित करता है। हम उस तालिका को वी-टेबल कहते हैं; आइए इसका तकनीकी नाम Base::__vtable दिखाएं। यदि कोई फ़ंक्शन पॉइंटर लक्ष्य हार्डवेयर प्लेटफ़ॉर्म पर एक मशीन शब्द में फिट बैठता है, तो Base::__vtable मेमोरी के 5 छिपे हुए शब्दों का उपभोग करेगा। प्रति उदाहरण 5 नहीं, प्रति समारोह 5 नहीं;

// Pseudo-code (not C++, not C) for a static table defined within file Base.cpp 

// Pretend FunctionPtr is a generic pointer to a generic member function 
// (Remember: this is pseudo-code, not C++ code) 
FunctionPtr Base::__vtable[5] = { 
    &Base::virt0, &Base::virt1, &Base::virt2, &Base::virt3, &Base::virt4 
}; 

चरण # 2: सिर्फ 5. यह निम्न छद्म कोड की तरह कुछ लग सकता है संकलक वर्ग बेस से प्रत्येक वस्तु के लिए एक छिपा सूचक (आमतौर पर यह भी एक मशीन-शब्द) कहते हैं। इसे वी-पॉइंटर कहा जाता है। एक छिपे हुए डेटा सदस्य के रूप में इस छिपे हुए सूचक के बारे में सोचो, जैसे कि संकलक कुछ इस तरह करने के लिए अपने वर्ग का पुनर्लेखन:

// Your original C++ source code 
class Base { 
public: 
    ... 
    FunctionPtr* __vptr; ← supplied by the compiler, hidden from the programmer 
    ... 
}; 

चरण # 3: संकलक this->__vptr प्रत्येक निर्माता भीतर initializes।

Base::Base(...arbitrary params...) 
    : __vptr(&Base::__vtable[0]) ← supplied by the compiler, hidden from the programmer 
    ... 
{ 
    ... 
} 

अब एक व्युत्पन्न वर्ग बाहर काम करते हैं: विचार, अपने वर्ग के वी-मेज पर बात करने के लिए प्रत्येक वस्तु के वी-सूचक पैदा करने के लिए जैसे कि वह प्रत्येक निर्माता की init-सूची में निम्नलिखित अनुदेश जोड़ता है। मान लीजिए कि आपका सी ++ कोड क्लास बेस से प्राप्त क्लास डर को परिभाषित करता है। कंपाइलर चरण # 1 और # 3 दोहराता है (लेकिन # 2 नहीं)। चरण # 1 में, कंपाइलर एक छिपी हुई वी-टेबल बनाता है, उसी फ़ंक्शन-पॉइंटर्स को Base::__vtable में रखते हुए, लेकिन ओवरराइड के अनुरूप उन स्लॉट को प्रतिस्थापित करता है। उदाहरण के लिए, डेर virt2() के माध्यम से virt0() ओवरराइड करता है और के रूप में किया जाता है दूसरों को विरासत में, डेर के वी-तालिका (नाटक डेर किसी भी नए virtuals नहीं जोड़ता है) कुछ इस तरह लग सकता है यदि:

// Pseudo-code (not C++, not C) for a static table defined within file Der.cpp 

// Pretend FunctionPtr is a generic pointer to a generic member function 
// (Remember: this is pseudo-code, not C++ code) 
FunctionPtr Der::__vtable[5] = { 
    &Der::virt0, &Der::virt1, &Der::virt2, &Base::virt3, &Base::virt4 
};          ^^^^----------^^^^---inherited as-is 

# 3 चरण में, कंपाइलर डर के प्रत्येक रचनाकारों की शुरुआत में एक समान सूचक-असाइनमेंट जोड़ता है। विचार प्रत्येक डर ऑब्जेक्ट के वी-पॉइंटर को बदलना है ताकि यह अपनी कक्षा की वी-टेबल पर इंगित करे। अंत में

, चलो कैसे देख सकते हैं (याद है, संकलक वर्ग डेर में चरण # 2 दोहराया नहीं जाता है यह एक दूसरे v-सूचक नहीं है, यह एक ही v-सूचक है कि आधार वर्ग, बेस में परिभाषित किया गया है।) संकलक वर्चुअल फ़ंक्शन को कॉल लागू करता है। आपका कोड इस प्रकार दिखाई देंगे:

// Your original C++ code 
void mycode(Base* p) 
{ 
    p->virt3(); 
} 

संकलक पता नहीं इस Base::virt3() या Der::virt3() या किसी अन्य व्युत्पन्न वर्ग भी है कि अभी तक अस्तित्व में नहीं है की शायद virt3() विधि कॉल करने के लिए जा रहा है या नहीं। यह केवल यह सुनिश्चित करने के लिए जानता है कि आप virt3() पर कॉल कर रहे हैं जो v-table के स्लॉट # 3 में फ़ंक्शन होता है। यह कुछ इस तरह में है कि कॉल का पुनर्लेखन:

// Pseudo-code that the compiler generates from your C++ 

void mycode(Base* p) 
{ 
    p->__vptr[3](p); 
} 

मैं दृढ़ता से पूछे जाने वाले प्रश्न पढ़ने के लिए हर सी ++ डेवलपर सलाह देते हैं। कुछ सप्ताह लग सकते हो सकता है (के रूप में इसे पढ़ने के लिए कठिन और लंबी है), लेकिन यह आप सी ++ और क्या इसके साथ किया जा सकता है के बारे में बहुत सिखा देगा।

1

सी वस्तु फ़ाइलों को पढ़ने से मुख्य अंतर यह है कि सी ++ विधि के नाम mangled हो रहा है। आप -C|--demangleobjdump के साथ विकल्प का उपयोग करने का प्रयास कर सकते हैं।

0

एक सी संरचना की तरह और एक अतिरिक्त पैरामीटर के साथ कार्यों का एक सेट जो संरचना के लिए सूचक है।

संकलक के बिना शायद निर्माण करने के लिए सबसे आसान तरीका है, तो कोड को डीबगर में लोड करें और मिश्रित स्रोत/असेंबलर मोड के साथ इसे चरणबद्ध करें।

हालांकि, संकलक का बिंदु यह है कि आपको यह सामान जानने की आवश्यकता नहीं है (जब तक कि आप एक कंपाइलर लिख रहे हों)।

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