segment bss en c

Dans l’une des réponses à la question ” Concernant le segment bss et le segment de données sous Unix “, l’explication suivante figure sur bss:

Bss est spécial: les objects .bss ne prennent pas d’espace dans le fichier d’object et, en regroupant tous les symboles qui ne sont pas spécifiquement initialisés ensemble, ils peuvent facilement être mis à zéro à la fois.

Mais lorsque j’utilise size sur le fichier object, généré à partir du code:

#include  int uninit_global_var; int init_global_var=5; int main() { int local_var; return 0; } 

J’ai le suivant

 text data bss dec hex filename 1231 280 12 1523 5f3 a.out 

et voyez le bss grandissant basé sur les membres de données non initialisés avec la scope globale. Alors, quelqu’un peut-il justifier la déclaration mentionnée?

Si vous supprimez stdio.h, votre sortie sera probablement plus significative. Ignorons cette bibliothèque, car elle contient des variables internes.

Dans votre cas spécifique, les événements suivants se produisent:

 int uninit_global_var; 

Comme il s’agit d’une variable allouée à la scope du fichier , sa durée de stockage statique est identique à celle de toute variable déclarée static . Le standard C exige que si une variable de durée de stockage statique n’est pas initialisée explicitement par le programmeur, comme dans ce cas, elle doit être définie sur zéro avant le démarrage du programme. Toutes ces variables sont placées dans le segment .bss .

 int init_global_var=5; 

Cette variable est également allouée à la scope du fichier, elle aura donc également une durée de stockage statique. Mais dans ce cas, il est initialisé par le programmeur. Le standard C exige que ces variables soient définies sur la valeur donnée avant le démarrage du programme. Ces variables sont placées dans le segment .data .

  int local_var; 

Cette variable a une durée de stockage automatique (locale). Le compilateur optimisera probablement cette variable car elle ne sert à rien. Mais supposons qu’une telle optimisation n’ait pas lieu. La variable sera ensuite allouée au moment de l’exécution, lorsque la scope (bloc) dans laquelle elle réside est exécutée, puis cesse d’exister une fois que cette étendue est complétée (elle sort de la scope). Il sera alloué soit sur la stack, soit dans un registre de la CPU. En d’autres termes, au moment du lien, cette variable n’existe que sous forme de code de programme, sous la forme d’une instruction d’assembleur disant “poussez un int sur la stack”, puis “extraire un int de la stack”.

La manière dont ces différents types de variables sont initialisés dépend du système. Mais en règle générale, le compilateur injecte du code avant que le nom principal ne soit appelé. C’est une simplification exagérée, mais pour des raisons pédagogiques, vous pouvez imaginer que votre programme ressemble en réalité à ceci:

 bss { int uninit_global_var; } data { int init_global_var; } rodata { 5; } int start_of_program (void) // called by OS { memset(bss, 0, bss_size); memcpy(data, rodata, data_size); return main(); } 

données: 4 bss: 4

Les systèmes embarqués dotés d’une vraie mémoire non volatile fonctionneront exactement comme le code ci-dessus, tandis que les systèmes basés sur RAM peuvent résoudre la partie d’initialisation des données différemment. bss fonctionne de la même manière sur tous les systèmes.


Vous pouvez facilement vérifier qu’ils sont stockés dans différents segments en exécutant le programme suivant:

 char uninit1; char uninit2; char init1 = 1; char init2 = 2; int main (void) { char local1 = 1; char local2 = 2; printf("bss\t%p\t%p\n", &uninit1, &uninit2); printf("data\t%p\t%p\n", &init1, &init2); printf("auto\t%p\t%p\n", &local1, &local2); } 

Vous verrez que les variables “uninit” sont allouées à des adresses adjacentes, mais à des adresses différentes des autres variables. Idem avec les variables “init”. Les variables “locales” peuvent être allouées n’importe où, ce qui vous permet d’obtenir n’importe quelle adresse étrange.

Je ne connais pas la réponse à coup sûr, mais mon hypothèse est la suivante:

La taille du segment bss se trouve dans le fichier object et est indiquée par la taille -> il doit être atsortingbué, après tout.

Mais le fichier object ne grossira pas lorsque le segment bss s’agrandira.

a.out n’est probablement pas un fichier object, c’est probablement un exécutable complet. Les objects relogeables, généralement nommés .o, sont des fichiers intermédiaires avant que le lien ne se produise. Voir l’option -c dans gcc.

Le segment bss augmente, mais vous n’avez pas besoin de ce segment dans votre binary (voir objcopy).

Donc, éventuellement, si vous mettiez ce code dans une sorte de ROM, il ne prendrait pas d’espace là-bas, mais aurait besoin d’espace dans la RAM (et du code pour l’initialiser à 0).