2016-11-16 10 views
5

कोड इस प्रकार हैं के लिए आभासी समारोह तालिका में ऑफसेट (सी ++ 11 कोड जी के साथ ++ संकलित - उबंटू 16.04 पर 5.4):आभासी आधार आभासी विरासत

#include <iostream> 

using namespace std; 



class Base 
{ 
    public: 
     virtual void show() 
     { 
      cout << "Base" << endl; 
     } 

     virtual void func() 
     { 
      cout << "func in Base" << endl; 
     } 

    protected: 
     int base = 15; 
}; 

class A: public virtual Base 
{ 
    public: 
     void show() override 
     { 
      cout << this << endl; 
      cout << 'A' << endl; 
     } 

     void func() override 
     { 
      cout << this << endl; 
      cout << "func in A" << endl; 
     } 

    protected: 
     int a = 31; 
}; 



int main(int argc, const char *argv[]) 
{ 
    A obj_a; 

    return 0; 
} 

मैं स्मृति लेआउट की जाँच करने के GDB उपयोग करने का प्रयास वस्तु "obj_a" के (सबसे पहले, मैं "पर सेट प्रिंट वस्तु", "प्रिंट सुंदर पर सेट", "पर प्रिंट vtbl सेट" सेट "सेट प्रिंट एएसएम-demangle पर" GDB में):

(gdb) p sizeof(obj_a) 
$1 = 32 
(gdb) x/8aw &obj_a 
0x7fffffffe320: 0x400d20 <vtable for A+24> 0x0 0x1f 0x0 
0x7fffffffe330: 0x400d50 <vtable for A+72> 0x0 0xf 0x0 

हम जानते हैं कि obj_a और उसके वर्चुअल बेस सबोबजेक्ट की शुरुआत के बीच ऑफसेट 16 बी (वर्चुअल बेस ऑफ़सेट) है। और फिर मैं जाँच एक की आभासी समारोह तालिका द्वारा 0x400d08 (0x400d20 - 24) कहा:

(gdb) x/14ag 0x400d08 
0x400d08 <vtable for A>: 0x10 0x0 
0x400d18 <vtable for A+16>: 0x400d90 <typeinfo for A> 0x400b46 <A::show()> 
0x400d28 <vtable for A+32>: 0x400b98 <A::func()> 0xfffffffffffffff0 
0x400d38 <vtable for A+48>: 0xfffffffffffffff0 0xfffffffffffffff0 
0x400d48 <vtable for A+64>: 0x400d90 <typeinfo for A> 0x400b8f <virtual thunk to A::show()> 
0x400d58 <vtable for A+80>: 0x400be1 <virtual thunk to A::func()>   0x400d20 <vtable for A+24> 
0x400d68 <VTT for A+8>: 0x400d50 <vtable for A+72> 0x0 

हम देख सकते हैं, वहाँ दो "को XXX में आभासी thunk", अर्थात् "0x400b8f" और "0x400be1" कर रहे हैं। मैं इन दो पतों में सहकर्मी हूं।

(gdb) x/3i 0x400b8f 
0x400b8f <virtual thunk to A::show()>: mov (%rdi),%r10 
0x400b92 <virtual thunk to A::show()+3>: add -0x18(%r10),%rdi 
0x400b96 <virtual thunk to A::show()+7>: jmp 0x400b46 <A::show()> 
(gdb) x/3i 0x400be1 
0x400be1 <virtual thunk to A::func()>: mov (%rdi),%r10 
0x400be4 <virtual thunk to A::func()+3>: add -0x20(%r10),%rdi 
0x400be8 <virtual thunk to A::func()+7>: jmp 0x400b98 <A::func()> 

मेरे प्रश्न हैं: क्या ", -0x18 (% R10) जोड़ने% RDI" और "-0x20 (% R10),% RDI जोड़ें" वास्तव में क्या मतलब है? -24 (-0x18) और -32 (-0x20) क्यों हैं? (मुझे लगता है कि वे सभी -16 होना चाहिए)

+1

मुझे लगता है कि आप कार्यों के कार्यान्वयन – Rerito

+0

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

+0

ओह, मुझे यह पता है। यहां इसे ऑफसेट को अप्रत्यक्ष तरीके से प्राप्त करने की आवश्यकता है। "vtbl - 0x18" आभासी फ़ंक्शन तालिका में ऑफ़सेट मान इंगित करता है। और फिर ऑफसेट जोड़कर "यह" को सही कर रहा है। – Jason

उत्तर

1

धन्यवाद रेरिटो, इसके बारे में खेद है।

मेरी समस्या यह है कि मैं असेंबली कोड से परिचित नहीं हूं।

(gdb) x/3i 0x400b8f 
0x400b8f <virtual thunk to A::show()>: mov (%rdi),%r10 
0x400b92 <virtual thunk to A::show()+3>: add -0x18(%r10),%rdi 
0x400b96 <virtual thunk to A::show()+7>: jmp 0x400b46 <A::show()> 

"वर्चुअल थंक टू ए :: शो()" के लिए असेंबली कोड में,% आरडीआई "यह" मान बचाता है। "mov (% rdi),% r10" का मतलब है "vptr" मान बढ़ाना (इसका पता "यह" है) r10 रजिस्टर में। "add -0x18 (% r10),% rdi" का अर्थ है कि वह मान जोड़ना जिसका पता "vptr - 24" (i.e. 0xfffffffffffffff0 वर्चुअल टेबल में) "इस" में है। तो "यह" मान ए के ऑब्जेक्ट के पते के रूप में सही किया जा सकता है।

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