Je suis intéressé par l'endroit où les littéraux de chaîne sont alloués / stockés.
J'ai trouvé une réponse intéressante ici , en disant:
La définition d'une chaîne en ligne intègre en fait les données dans le programme lui-même et ne peut pas être modifiée (certains compilateurs le permettent par une astuce intelligente, ne vous inquiétez pas).
Mais, cela avait à voir avec C ++, sans oublier que cela dit de ne pas déranger.
Je dérange. = D
Ma question est donc où et comment ma chaîne littérale est-elle conservée? Pourquoi ne devrais-je pas essayer de le modifier? La mise en œuvre varie-t-elle selon la plate-forme? Quelqu'un souhaite-t-il élaborer sur le «truc intelligent»?
la source
foo = "hello"
dans ce cas) peut provoquer des effets secondaires involontaires ... (en supposant que vous ne allouer de la mémoire avecnew
ou quelque chose)char *p = "abc";
pour créer des chaînes mutables comme le dit différemment @ChrisCooperIl n'y a pas de réponse unique à cela. Les normes C et C ++ disent simplement que les littéraux de chaîne ont une durée de stockage statique, toute tentative de les modifier donne un comportement indéfini, et plusieurs littéraux de chaîne avec le même contenu peuvent partager ou non le même stockage.
Selon le système pour lequel vous écrivez et les capacités du format de fichier exécutable qu'il utilise, ils peuvent être stockés avec le code de programme dans le segment de texte, ou ils peuvent avoir un segment distinct pour les données initialisées.
La détermination des détails variera également en fonction de la plate-forme - incluez très probablement des outils qui peuvent vous dire où cela se trouve. Certains vous donneront même le contrôle sur des détails comme ça, si vous le souhaitez (par exemple, gnu ld vous permet de fournir un script pour tout dire sur la façon de regrouper les données, le code, etc.)
la source
movb $65, 8(%esp); movb $66, 9(%esp); movb $0, 10(%esp)
pour la chaîne"AB"
, mais la grande majorité du temps, ce sera dans un segment non-code tel que.data
ou.rodata
ou similaire (selon que la cible prend en charge ou non segments en lecture seule).Pourquoi ne devrais-je pas essayer de le modifier?
Parce que c'est un comportement indéfini. Citation de C99 N1256 draft 6.7.8 / 32 "Initialisation" :
Où vont-ils?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
char s[]
: pilechar *s
:.rodata
section du fichier objet.text
section du fichier objet est vidée, qui a des autorisations de lecture et d'exécution, mais pas d'écritureProgramme:
Compilez et décompilez:
La sortie contient:
La chaîne est donc stockée dans la
.rodata
section.Ensuite:
Contient (simplifié):
Cela signifie que le script de l'éditeur de liens par défaut vide à la fois
.text
et.rodata
dans un segment qui peut être exécuté mais pas modifié (Flags = R E
). Tenter de modifier un tel segment conduit à un segfault sous Linux.Si nous faisons de même pour
char[]
:on obtient:
il est donc stocké dans la pile (par rapport à
%rbp
), et nous pouvons bien sûr le modifier.la source
FYI, juste pour sauvegarder les autres réponses:
La norme: ISO / CEI 14882: 2003 dit:
la source
gcc crée une
.rodata
section qui est mappée "quelque part" dans l'espace d'adressage et qui est marquée en lecture seule,Visual C ++ (
cl.exe
) crée une.rdata
section dans le même but.Vous pouvez consulter la sortie de
dumpbin
ouobjdump
(sous Linux) pour voir les sections de votre exécutable.Par exemple
la source
printf("some null terminated static string");
au lieu deprintf(*address);
C)Cela dépend du format de votre exécutable . Une façon d'y penser est que si vous programmiez un assemblage, vous pourriez mettre des littéraux de chaîne dans le segment de données de votre programme d'assemblage. Votre compilateur C fait quelque chose comme ça, mais tout dépend du système pour lequel vous êtes compilé.
la source
Les littéraux de chaîne sont fréquemment alloués à la mémoire en lecture seule, ce qui les rend immuables. Cependant, dans certains compilateurs, la modification est possible par une "astuce intelligente" .. Et l'astuce intelligente consiste à "utiliser un pointeur de caractère pointant vers la mémoire" .. rappelez-vous que certains compilateurs, peuvent ne pas permettre cela..Voici la démo
la source
Comme cela peut différer d'un compilateur à l'autre, le meilleur moyen est de filtrer un vidage d'objet pour le littéral de chaîne recherché:
où
-s
obligeobjdump
à afficher le contenu complet de toutes les sections,main.o
est le fichier objet,-B 1
forcegrep
à imprimer également une ligne avant la correspondance (pour que vous puissiez voir le nom de la section) etstr
est le littéral de chaîne que vous recherchez.Avec gcc sur une machine Windows, et une variable déclarée
main
commefonctionnement
Retour
la source