Purpose of static_initialization_and_destruction a

2019-05-12 08:51发布

问题:

The following is the C++ source code. The code has a class HumanBeing and with Display and verify functions. Each function prints statements.

#include <iostream>

using namespace std;

class HumanBeing {
public:
    void display() {
        cout << "hello aam a human being" << endl;
    }
    void print() {
        cout << "verify print" << endl;
    }
};

int main() {
    HumanBeing vamshi;

    vamshi.display();
    vamshi.print();
    return 0;
}

This is the corresponding assembly code of the above c++ code

        .file   "verify.cpp"
        .local  _ZStL8__ioinit
        .comm   _ZStL8__ioinit,1,1
        .section        .rodata
.LC0:
        .string "hello aam a human being"
        .section        .text._ZN10HumanBeing7displayEv,"axG",@progbits,_ZN10HumanBeing7displayEv,comdat
        .align 2
        .weak   _ZN10HumanBeing7displayEv
        .type   _ZN10HumanBeing7displayEv, @function
_ZN10HumanBeing7displayEv:
.LFB971:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %rdi, -8(%rbp)
        movl    $.LC0, %esi
        movl    $_ZSt4cout, %edi
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
        movq    %rax, %rdi
        call    _ZNSolsEPFRSoS_E
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE971:
        .size   _ZN10HumanBeing7displayEv, .-_ZN10HumanBeing7displayEv
        .section        .rodata
.LC1:
        .string "verify print"
        .section        .text._ZN10HumanBeing5printEv,"axG",@progbits,_ZN10HumanBeing5printEv,comdat
        .align 2
        .weak   _ZN10HumanBeing5printEv
        .type   _ZN10HumanBeing5printEv, @function
_ZN10HumanBeing5printEv:
.LFB972:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %rdi, -8(%rbp)
        movl    $.LC1, %esi
        movl    $_ZSt4cout, %edi
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
        movq    %rax, %rdi
        call    _ZNSolsEPFRSoS_E
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE972:
        .size   _ZN10HumanBeing5printEv, .-_ZN10HumanBeing5printEv
        .text
        .globl  main
        .type   main, @function
main:
.LFB973:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        leaq    -1(%rbp), %rax
        movq    %rax, %rdi
        call    _ZN10HumanBeing7displayEv
        leaq    -1(%rbp), %rax
        movq    %rax, %rdi
        call    _ZN10HumanBeing5printEv
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE973:
        .size   main, .-main
        .type   _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB982:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        cmpl    $1, -4(%rbp)
        jne     .L5
        cmpl    $65535, -8(%rbp)
        jne     .L5
        movl    $_ZStL8__ioinit, %edi
        call    _ZNSt8ios_base4InitC1Ev
        movl    $__dso_handle, %edx
        movl    $_ZStL8__ioinit, %esi
        movl    $_ZNSt8ios_base4InitD1Ev, %edi
        call    __cxa_atexit
.L5:
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE982:
        .size   _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
        .type   _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB983:
        .cfi_startproc

In this code the I have the following doubts:

1.static_initialization_and_destruction -- seems to be function, but its exact working is not clearly understood

  1. Purpose and working of GLOBAL__sub_I_main function is not clearly understood.

Could anyone clearly explain the working and organisation of constructor and destructor in this code and purpose of GLOBAL__sub_I_main function ?

回答1:

Both functions are used by gcc in C++ for any instantiated classes with static storage duration that need to be constructed before main e.g.

class A {
    A();
    ~A();
    ... 
};

A a;

// "a" will need to be constructed before main
int main()
{
    return a.Foo();
}
// "a" will need to be destructed after main

The generated _Z41__static_initialization_and_destruction_0ii function (demangled __static_initialization_and_destruction_0(int, int)) serves 2 purposes:

  • Call any constructors of classes with static storage duration in the preprocessed/compiled C++ source file (when required)
  • Register destructors of classes with static storage duration in the preprocessed/compiled C++ source file (when required) as exit functions via atexit.

_GLOBAL__sub_I_main is a simple wrapper function around it, who's function-pointer is added to the .init_array section. When compiling multiple source files, each individual object file will add initialization functions to the .init_array and all of those functions will be called before main is called.

While this may not be immediately obvious your code contains an instance with static storage duration. The <iostream> header file declares std::ios_base::Init which needs to be constructed as early as possible to make it safe to access the standard I/O streams in the constructors and destructors of static objects.