2011-10-08 8 views
11

pimpl idiom आमतौर पर आदेश ABI संगतता को तोड़ने और सभी कोड है कि पुस्तकालय पर निर्भर करता है पुन: संयोजित किए बिना गतिशील रूप से जुड़ा हुआ पुस्तकालयों में कोड को बदलने की अनुमति के लिए प्रयोग किया जाता है।एक निजी सदस्य परिवर्तनीय ब्रेक सी ++ एबीआई संगतता कैसे जोड़ता है?

explanations में से अधिकांश का उल्लेख है कि एक नया निजी सदस्य परिवर्तक कक्षा में सार्वजनिक और निजी सदस्यों के ऑफसेट को बदलता है। मेरे लिए उसका मतलब बनता है। जो मुझे समझ में नहीं आता है यह है कि अभ्यास में यह वास्तव में निर्भर पुस्तकालयों को तोड़ देता है।

मैं ELF फ़ाइलें और कैसे गतिशील जोड़ने वास्तव में काम करता है पर पढ़ने का एक बहुत कुछ किया है, लेकिन मैं अभी भी नहीं दिख रहा है कि कैसे साझा lib में कक्षा आकार बदलने चीजें टूट जाएगा।

उदा।

[email protected]:~/pimpl$ objdump -d -j .text a.out 
08048874 <main>: 
... 
8048891: e8 b2 fe ff ff   call 8048748 <[email protected]> 

some_method करने के लिए कॉल प्रक्रियात्मक लिंकेज टेबल (PLT) का उपयोग करता है:: यहाँ एक परीक्षण आवेदन (a.out) मैं ने लिखा है कि एक परीक्षण साझा लाइब्रेरी (libInterface.so) से कोड (Interface::some_method) का उपयोग करता है

[email protected]:~/pimpl$ objdump -d -j .plt a.out 

08048748 <[email protected]>: 
8048748: ff 25 1c a0 04 08  jmp *0x804a01c 
804874e: 68 38 00 00 00   push $0x38 
8048753: e9 70 ff ff ff   jmp 80486c8 <_init+0x30> 

जो बाद में वैश्विक ऑफसेट तालिका (GOT) जहां पता 0x804a01c निहित है को जाता है:

[email protected]:~/pimpl$ readelf -x 24 a.out 

Hex dump of section '.got.plt': 
    0x08049ff4 089f0408 00000000 00000000 de860408 ................ 
    0x0804a004 ee860408 fe860408 0e870408 1e870408 ................ 
    0x0804a014 2e870408 3e870408 4e870408 5e870408 ....>...N...^... 
    0x0804a024 6e870408 7e870408 8e870408 9e870408 n...~........... 
    0x0804a034 ae870408       .... 

और फिर यहीं गतिशील लिंकर wo libInterface.so में Interface::some_method पाता है और GOT में अपने कोड some_method के बाद कॉल पर इतना लोड करता है अपना जादू rks और सभी LD_LIBRARY_PATH में साझा libs में निहित प्रतीकों के माध्यम से लग रहा है,, GOT में कोड वास्तव में से साझा कोड खंड है पुस्तकालय।

या उन पंक्तियों के साथ कुछ।

लेकिन ऊपर दिए गए, मैं अभी भी समझ में नहीं आता कि कैसे साझा लिब के वर्ग के आकार या उसके विधि ऑफसेट खेलने में यहाँ आते हैं। जहां तक ​​मैं कह सकता हूं, ऊपर दिए गए कदम कक्षा के आकार के लिए अज्ञेयवादी हैं। ऐसा लगता है कि लाइब्रेरी में विधि के नाम का प्रतीक केवल एक .out में शामिल है। क्लास आकार में किसी भी बदलाव को रनटाइम पर हल किया जाना चाहिए जब लिंकर कोड को GOT में लोड करता है, नहीं?

मुझे यहां क्या याद आ रही है?

उत्तर

15

मुख्य समस्या यह है कि, जब आप किसी वर्ग का एक नया उदाहरण आवंटित करते हैं (या तो स्टैक पर, या new के माध्यम से), कॉलिंग कोड को ऑब्जेक्ट के आकार को जानने की आवश्यकता होती है। यदि आप बाद में ऑब्जेक्ट का आकार बदलते हैं (एक निजी सदस्य जोड़कर), यह आवश्यक आकार बढ़ाता है; हालांकि आपके कॉलर अभी भी पुराने आकार का उपयोग कर रहे हैं। तो आप ऑब्जेक्ट को पकड़ने के लिए पर्याप्त स्थान आवंटित नहीं करते हैं, और ऑब्जेक्ट का कन्स्ट्रक्टर तब स्टैक (या ढेर) को दूषित करने के लिए आगे बढ़ता है, क्योंकि ऐसा लगता है कि इसमें पर्याप्त स्थान है।

इसके अतिरिक्त, यदि आपके पास कोई इनलाइन सदस्य फ़ंक्शन है, तो उनके कोड (सदस्य चर के ऑफसेट सहित) को कॉलिंग कोड में रेखांकित किया जा सकता है। यदि आप अंत के अलावा कहीं भी निजी सदस्यों को जोड़ते हैं, तो इन ऑफसेट गलत होंगे, जिससे स्मृति भ्रष्टाचार भी हो सकता है (नोट: भले ही आप अंत में जोड़ दें, आकार का मिलान अभी भी एक समस्या है)।

+0

अहा! समझ गया। दरअसल, इंटरफेस के सीटीआर को बुलाए जाने से पहले डिस्सेप्लिब्स में थोड़ा और आगे देखकर, मैं ऑब्जेक्ट के लिए स्पेस आवंटित कर सकता हूं (इस मामले में 4bytes)। – adg

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