.bss vs COMMON: où va-t-on?

De mon livre:

.bss:

Variables C globales non initialisées

COMMUN:

Objets de données non institutionnalisés non encore alloués

Je dois dire que je ne vois pas vraiment de distinction claire. Je ne comprends même pas tout à fait ce qu’est un object de données non initié, non alloué … ne ressemble à rien. J’ai utilisé l’outil de readelf de GNU pour essayer de regarder un code C simple, mais je ne peux pas trouver un seul symbole COMMON. J’ai lu des choses comme le type COMMON de FORTRAN est un exemple de symbole COMMON – mais je ne connais pas FORTRAN

Quelqu’un peut-il éventuellement distinguer les deux pour moi? Si possible, si possible avec un exemple C? Très appréciée.

edit : à partir de ce post, la variable c ici:

 int c; int main() {} ... 

devrait être COMMUN. Mais utiliser objdump -t montre pour moi que c est en .bss …

confus

 // file ac // file-scope int a = 0; // goes into BSS 

après la compilation de ac dans le fichier object ao , a symbole passe dans la section BSS.

 // file bc // file-scope int b; // goes into COMMON section 

après la compilation de bc dans le fichier object bo , le symbole b entre dans la section COMMON.

Après la liaison de ao et de bo , les symboles a et b entrent dans la section BSS. Les symboles communs n’existent que dans les fichiers objects, pas dans les fichiers exécutables. L’idée des symboles COMMUN sous Unix est de permettre plusieurs définitions externes d’une même variable (dans différentes unités de compilation) sous un seul symbole commun dans certaines conditions.

Les biens communs n’apparaissent qu’avant l’étape des liens. Les biens communs sont ce que plus tard va dans le bss ou data ‚mais c’est à l’éditeur de liens de décider où ça va. Cela vous permet de définir la même variable dans différentes unités de compilation. Autant que je sache, il s’agit principalement d’autoriser certains anciens fichiers d’en-tête qui avaient int foo; en eux au lieu de extern int foo; .

Voici comment ça fonctionne:

 $ cat > ac int foo; $ cat > bc int foo; $ cat > main.c extern int foo; int main(int argc, char **argv) { return foo; } $ cc -c ac && cc -c bc && cc -c main.c && cc -ox ao bo main.o $ objdump -t ao | grep foo 0000000000000004 O *COM* 0000000000000004 foo $ objdump -t bo | grep foo 0000000000000004 O *COM* 0000000000000004 foo $ objdump -tx | grep foo 0000000000600828 g O .bss 0000000000000004 foo $ 

Notez que cela ne fonctionne que si au plus une des variables des différentes unités de compilation est initialisée.

 $ echo "int foo = 0;" > ac $ cc -c ac && cc -c bc && cc -c main.c && cc -ox ao bo main.o $ echo "int foo = 0;" > bc $ cc -c ac && cc -c bc && cc -c main.c && cc -ox ao bo main.o bo:(.bss+0x0): multiple definition of `foo' ao:(.bss+0x0): first defined here collect2: ld returned 1 exit status $ 

Cela fait peur, la compatibilité avec les systèmes anciens et vous ne devriez jamais vous en fier. Faites les choses correctement – une seule définition des variables globales dans toutes les unités de compilation, déclarez-le extern partout ailleurs via un en-tête.

Si vous autorisez common lors de la liaison, différentes unités peuvent déclarer la même variable et l’éditeur de liens les localisera au même endroit. Les types n’ont même pas besoin d’être identiques, il s’agit donc d’une sorte d’union de temps de liaison. C’est la caractéristique commune de Fortran. Si vous n’autorisez pas common liaison de C, une telle situation entraînera une erreur de temps de liaison. Une telle liaison common n’est possible que pour les globaux non initialisés, car sinon, l’initialisation à effectuer n’est pas claire.

Les globales allant à bss sont juste des globales non initialisées que C définit comme étant initialisées à 0. La plupart des formats d’object supportent les sections où seule la taille est donnée et le chargeur remplit la section entière de zéros.

PS: Si vous utilisez gcc vous pouvez utiliser l’option -fno-common pour imposer common symboles common à la section bss , ce qui, comme le soutient Art, est une bonne pratique.

Les variables statiques se retrouvent dans la section .bss.Les variables globales non initialisées (non statiques) sont placées dans la section .common.

 static a; //bss int c; //.common main(){ }