Sé que han pasado casi dos años desde que se hizo esta pregunta, pero tuve que descubrir la mecánica de la inicialización de C++ con GCC, así que pensé en compartir los detalles aquí. Resulta que hay mucha información desactualizada o confusa en la web. Por ejemplo, el contenedor collect2
mencionado anteriormente no parece usarse para objetivos ARM ELF, ya que su soporte de sección arbitrario permite el enfoque descrito a continuación.
En primer lugar, cuando compilo el código anterior con la línea de comandos dada usando Sourcery Codebench Lite 2.012,09-63, veo el tamaño .init_array
sección correcta de 4:
$ arm-none-eabi-objdump -h foo.o
foo.o: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
...
13 .init_array 00000004 00000000 00000000 0000010c 2**2
CONTENTS, ALLOC, LOAD, RELOC, DATA
...
Cuando miro a los contenidos de este apartado , que sólo contiene 0:
$ arm-none-eabi-objdump -j .init_array -s foo.o
Contents of section .init_array:
0000 00000000 ....
Sin embargo, también hay una sección de reubicación que establece correctamente para _GLOBAL__sub_I_foo
:
$ arm-none-eabi-objdump -x foo.o
...
RELOCATION RECORDS FOR [.init_array]:
OFFSET TYPE VALUE
00000000 R_ARM_TARGET1 _GLOBAL__sub_I_foo
En general, .init_array
puntos a todos sus talones de _GLOBAL__sub_I_XXX
inicializador, cada uno de ellos llama a su propia copia de _Z41__static_initialization_and_destruction_0ii
(sí, está definido multiplicar), que llama al constructor con los argumentos adecuados.
porque estoy usando -nostdlib
en mi construcción, no puedo usar CodeSourcery de __libc_init_array
para ejecutar el .init_array
para mí, así que tengo que llamar a los inicializadores estáticos a mí mismo:
extern "C"
{
extern void (**__init_array_start)();
extern void (**__init_array_end)();
inline void static_init()
{
for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
(*p)();
}
}
__init_array_start
y __init_array_end
se definen por el guión de enlazado:
. = ALIGN(4);
.init_array :
{
__init_array_start = .;
KEEP (*(.init_array*))
__init_array_end = .;
}
Este enfoque parece funcionar tanto con el CodeSourcery compilador cruzado y GCC ARM nativo, por ejemplo, en Ubuntu 12.10 para ARM. La compatibilidad con ambos compiladores es una razón para usar -nostdlib
y no depender del soporte desnudo de CodeSourcery CS3.
No cree que gcc sea lo suficientemente inteligente como para 1) ver que el valor es 100, o 2) ver que el valor simplemente se incrementa pero nunca se usa ? –
@Bo Persson: Es por eso que agregué la opción -O0, por lo que gcc no lo optimizará. –