| |||
| Home > The ARM C and C++ libraries > C++ initialization, construction and destruction | |||
The C++ Standard places certain requirements on the construction and destruction of objects with static storage duration.
The ARM C++ compiler uses the .init_array area
to achieve this. This is a const data array of self-relative
pointers to functions. For example, you might have the following
C++ translation unit, contained in the file test.cpp:
struct T
{
T();
~T();
} t;
int f()
{
return 4;
}
int i = f();
This translates into the following pseudocode:
AREA ||.text||, CODE, READONLY
int f()
{
return 4;
}
static void __sti___8_test_cpp
{
// construct 't' and register its destruction
__aeabi_atexit(T::T(&t), &T::~T, &__dso_handle);
i = f();
}
AREA ||.init_array||, DATA, READONLY
DCD __sti___8_test_cpp - {PC}
AREA ||.data||, DATA
t % 4
i % 4
This pseudocode is for illustration only. To see the code
that is generated, compile the C++ source code with armcc -c --cpp -S.
The linker collects each .init_array from
the various translation units together. It is important that the .init_array is
accumulated in the same order.
The library routine __cpp_initialize__aeabi_ is
called from the C library startup code, __rt_lib_init,
before main. __cpp_initialize__aeabi_ walks
through the .init_array calling each function
in turn. On exit, __rt_lib_shutdown calls __cxa_finalize.
Usually, there is at most one function for T::T(),
mangled name _ZN1TC1Ev, one function for T::~T(),
mangled name _ZN1TD1Ev, one __sti__ function,
and four bytes of .init_array for each translation
unit. The mangled name for the function f() is _Z1fv.
There is no way to determine the initialization order between translation
units.
Function-local static objects with destructors are also handled
using __aeabi_atexit.
.init_array sections must be placed
contiguously within the same region for their base and limit symbols
to be accessible. If they are not, the linker generates an error.