Appel du constructeur global ne figurant pas dans la section .init_array

J’essaie d’append un support de constructeur global sur une cible intégrée (ARM Cortex-M3). Disons que j’ai le code suivant:

class foobar { int i; public: foobar() { i = 100; } void inc() { i++; } }; foobar foo; int main() { foo.inc(); for (;;); } 

Je le comstack comme ceci:

 arm-none-eabi-g++ -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -c foo.cpp -o foo.o 

Quand je regarde la section .init_array avec objdump, il montre que la section .init_section a une taille nulle.

Je reçois un symbole nommé _Z41__static_initialization_and_destruction_0ii . Lorsque je désassemble le fichier object, je constate que la construction globale est effectuée dans le symbole static_initialization_and_destruction.

Pourquoi un pointeur n’est-il pas ajouté à ce symbole dans la section .init_s?

Je sais que cela fait presque deux ans que cette question a été posée, mais je devais comprendre la mécanique de l’initialisation C ++ en métal nu avec GCC, alors j’ai pensé partager les détails ici. Il s’avère qu’il ya beaucoup d’informations obsolètes ou confuses sur le Web. Par exemple, l’encapsuleur collect2 souvent mentionné ne semble pas être utilisé pour les cibles ELF ARM, car sa prise en charge de section arbitraire active l’approche décrite ci-dessous.

Tout d’abord, lorsque je comstack le code ci-dessus avec la ligne de commande donnée à l’aide de Sourcery CodeBench Lite 2012.09-63, la taille de la section .init_array de 4 est correcte:

 $ 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 ... 

Quand je regarde le contenu de la section, elle ne contient que 0:

 $ arm-none-eabi-objdump -j .init_array -s foo.o Contents of section .init_array: 0000 00000000 .... 

Cependant, il existe également une section de relocalisation qui le définit correctement à _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 général, .init_array pointe vers tous vos _GLOBAL__sub_I_XXX initialisation _GLOBAL__sub_I_XXX , chacun appelant sa propre copie de _Z41__static_initialization_and_destruction_0ii (oui, il est défini de manière multiple), qui appelle le constructeur avec les arguments appropriés.

Comme j’utilise -nostdlib dans ma construction, je ne peux pas utiliser __libc_init_array de __libc_init_array pour exécuter le .init_array pour moi. Je dois donc appeler les initialiseurs statiques moi-même:

 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 et __init_array_end sont définis par le script de l'éditeur de liens:

 . = ALIGN(4); .init_array : { __init_array_start = .; KEEP (*(.init_array*)) __init_array_end = .; } 

Cette approche semble fonctionner à la fois avec le compilateur croisé CodeSourcery et avec ARM GCC natif, par exemple dans Ubuntu 12.10 pour ARM. La prise en charge des deux compilateurs est l'une des raisons d'utiliser -nostdlib et de ne pas compter sur le support en métal nu CodeSourcery CS3.

Timmmm,

Je viens d’avoir le même problème sur le nRF51822 et je l’ai résolu en ajoutant KEEP () autour de quelques lignes dans le fichier Nordic .ld d’origine:

 KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) 

Pendant ce temps, j’ai fait la même chose pour la zone fini_array aussi. Résolu mon problème et l’éditeur de liens peut toujours supprimer d’autres sections inutilisées …

Vous avez uniquement produit un fichier object, en raison de l’argument -c de gcc. Pour créer la section .init, je pense que vous devez associer ce fichier .o à un exécutable réel ou à une bibliothèque partagée. Essayez de supprimer l’argument -c et de renommer le fichier de sortie en “foo”, puis vérifiez le fichier exécutable résultant avec le désassembleur.

Si vous regardez attentivement, _Z41__static_initialization_and_destruction_0ii sera appelée dans le constructeur global. Quel type de fichier serait lié à la section .init_array (dans arm-none-eabi- de CodeSourcery.) Ou à une autre fonction ( __main() si vous utilisez Linux g ++). () Ceci devrait être appelé au démarrage ou à main() . Voir aussi ce lien.

J’ai eu un problème similaire où mes constructeurs n’étaient pas appelés (nRF51822 Cortex-M0 avec GCC). Le problème s’est avéré être dû à cet indicateur d’éditeur de liens:

  -Wl,--gc-sections 

Ne me demande pas pourquoi! Je pensais qu’il ne supprimait que le code mort.