2014-06-30 3 views
2

J'essaie actuellement de comprendre comment G ++ génère un assemblage à partir d'un petit exemple de programme C++. Donc, je teste le programm suivant avec diverses optimisations:Destructeurs en double dans la sortie Assembler pour C++

#define noinline __attribute__ ((noinline)) 

class Test_Base { 
public: 
    noinline Test_Base() {} 
    virtual noinline ~Test_Base() {} 
    void noinline method() { v_method(); } 
private: 
    virtual void v_method()=0; 
}; 

class Test1 
    : public Test_Base 
{ 
public: 
    noinline Test1() {} 
    noinline ~Test1() {} 
private: 
    void noinline v_method() {} 
}; 

class Test2 
    : public Test_Base 
{ 
public: 
    noinline Test2() {} 
    ~Test2() {} 
private: 
    void noinline v_method() {} 
}; 

int main() { 
    volatile int x = 0; 
    Test_Base * b; 
    Test1 t1; 
    Test2 t2; 
    if(x) 
     b = &t1; 
    else 
     b = &t2; 
    b->method(); 
    return 0; 
} 

recherche Toutefois, à ce code (compilé à l'aide -Os pour la Plattform ARMv7), je trouve que toutes les définitions des constructeurs et destructeurs ont été inclus à plusieurs reprises. Voici les parties pertinentes de la table de symboles pour Test1:

00008730 w F .text 00000004    Test1::v_method() 
000088d8 w O .rodata  00000014    vtable for Test1 
000087d0 w F .text 00000020    Test1::Test1() 
00008774 w F .text 0000001c    Test1::~Test1() 
00008710 w F .text 00000020    Test1::~Test1() 
000088a4 w O .rodata  00000007    typeinfo name for Test1 
00008898 w O .rodata  0000000c    typeinfo for Test1 
000087d0 w F .text 00000020    Test1::Test1() 
00008710 w F .text 00000020    Test1::~Test1() 

J'ai donc un constructeur et deux (les deux Destructeurs derniers appels ne sont que de dupliquer tat les mêmes positions que précédemment). En regardant l'ensemble je constate ce qui suit:

premier constructeur

000087d0 <Test1::Test1()>: 
    87d0:  e92d4010  push {r4, lr} 
    87d4:  e1a04000  mov  r4, r0 
    87d8:  ebfffff3  bl  87ac <Test_Base::Test_Base()> 
    87dc:  e1a00004  mov  r0, r4 
    87e0:  e59f3004  ldr  r3, [pc, #4] ; 87ec <Test1::Test1()+0x1c> 
    87e4:  e5843000  str  r3, [r4] 
    87e8:  e8bd8010  pop  {r4, pc} 
    87ec:  000088e0  .word 0x000088e0 

Je suppose que cela fait ce que je l'ai dit de faire.

Maintenant, le destructor à 0x8710:

00008710 <Test1::~Test1()>: 
    8710:  e59f3014  ldr  r3, [pc, #20] ; 872c <Test1::~Test1()+0x1c> 
    8714:  e92d4010  push {r4, lr} 
    8718:  e1a04000  mov  r4, r0 
    871c:  e5803000  str  r3, [r0] 
    8720:  ebfffff6  bl  8700 <Test_Base::~Test_Base()> 
    8724:  e1a00004  mov  r0, r4 
    8728:  e8bd8010  pop  {r4, pc} 
    872c:  000088e0  .word 0x000088e0 

Encore une fois il n'y a rien de suspect ici.

Maintenant, le destructor à 0x8774:

00008774 <Test1::~Test1()>: 
    8774:  e92d4010  push {r4, lr} 
    8778:  e1a04000  mov  r4, r0 
    877c:  ebffffe3  bl  8710 <Test1::~Test1()> 
    8780:  e1a00004  mov  r0, r4 
    8784:  ebffff69  bl  8530 <_init+0x44> 
    8788:  e1a00004  mov  r0, r4 
    878c:  e8bd8010  pop  {r4, pc} 

Je ne peux pas dire ce que cela fait vraiment, comme je ne suis pas vraiment au courant de l'ABI. Je suppose qu'il a quelque chose à voir avec l'initialisation statique.

Quel est l'objectif de ce destructeur supplémentaire?

Si je compile la même chose pour x86_64, j'ai aussi des destructeurs dupliqués, donc cela ne semble pas spécifique au système.

Répondre

2

Le premier est un destructeur non virtuel, utilisé pour détruire des objets automatiques ou statiques lorsque le type dynamique est connu au moment de la compilation.

La seconde est un "thunk" virtuel utilisé pour la suppression polymorphe. Il appelle le destructeur non-virtuel pour destoyer l'objet, puis appelle operator delete pour libérer la mémoire.