Estoy interesado en dónde se asignan / almacenan los literales de cadena.
Encontré una respuesta intrigante aquí , diciendo:
Definir una cadena en línea en realidad incrusta los datos en el propio programa y no se puede cambiar (algunos compiladores lo permiten mediante un truco inteligente, no te molestes).
Pero, tenía que ver con C ++, sin mencionar que dice no molestarse.
Estoy molestando = D
Entonces, mi pregunta es dónde y cómo se mantiene mi cadena literal. ¿Por qué no debería intentar alterarlo? ¿La implementación varía según la plataforma? ¿Alguien quiere explicar el "truco inteligente"?
fuente
foo = "hello"
en este caso) puede causar efectos secundarios no deseados ... (suponiendo que no esté rea asignar memoria connew
o algo)char *p = "abc";
para hacer que las cadenas mutables como se ha dicho de manera diferente por @ChrisCooperNo hay una respuesta para esto. Los estándares C y C ++ solo dicen que los literales de cadena tienen una duración de almacenamiento estático, cualquier intento de modificarlos da un comportamiento indefinido, y múltiples literales de cadena con el mismo contenido pueden o no compartir el mismo almacenamiento.
Dependiendo del sistema para el que está escribiendo y las capacidades del formato de archivo ejecutable que utiliza, pueden almacenarse junto con el código del programa en el segmento de texto, o pueden tener un segmento separado para los datos inicializados.
La determinación de los detalles también variará dependiendo de la plataforma; lo más probable es que incluyan herramientas que puedan indicarle dónde se encuentra. Algunos incluso le darán control sobre detalles como ese, si lo desea (por ejemplo, gnu ld le permite proporcionar un script para contarle todo sobre cómo agrupar datos, código, etc.)
fuente
movb $65, 8(%esp); movb $66, 9(%esp); movb $0, 10(%esp)
para la cadena"AB"
, pero la gran mayoría de las veces, estará en un segmento sin código como.data
o.rodata
o similar (dependiendo de si el destino admite o no segmentos de solo lectura).¿Por qué no debería intentar alterarlo?
Porque es un comportamiento indefinido. Cita del C99 N1256 borrador 6.7.8 / 32 "Inicialización" :
¿A dónde van?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
char s[]
: apilarchar *s
:.rodata
sección del archivo objeto.text
sección del archivo objeto, que tiene permisos de lectura y ejecución, pero no escrituraPrograma:
Compilar y descompilar:
La salida contiene:
Entonces la cadena se almacena en el
.rodata
sección.Luego:
Contiene (simplificado):
Esto significa que la secuencia de comandos enlazador predeterminado vertederos tanto
.text
y.rodata
en un segmento que se puede ejecutar pero sin modificar (Flags = R E
). Intentar modificar un segmento de este tipo conduce a un defecto en Linux.Si hacemos lo mismo para
char[]
:obtenemos:
por lo que se almacena en la pila (en relación con
%rbp
) y, por supuesto, podemos modificarlo.fuente
FYI, solo respaldando las otras respuestas:
El estándar: ISO / IEC 14882: 2003 dice:
fuente
gcc crea una
.rodata
sección que se asigna "en algún lugar" en el espacio de direcciones y está marcada como de solo lectura,Visual C ++ (
cl.exe
) hace un.rdata
sección con el mismo propósito.Puede mirar la salida desde
dumpbin
oobjdump
(en Linux) para ver las secciones de su ejecutable.P.ej
fuente
printf("some null terminated static string");
lugar deprintf(*address);
en C)Depende del formato de su ejecutable . Una forma de pensarlo es que si estuviera programando ensamblaje, podría colocar literales de cadena en el segmento de datos de su programa ensamblador. Su compilador de C hace algo así, pero todo depende de para qué sistema se está compilando el binario.
fuente
Los literales de cadena se asignan con frecuencia a la memoria de solo lectura, lo que los hace inmutables. Sin embargo, en algunos compiladores la modificación es posible mediante un "truco inteligente" ... Y el truco inteligente es "usar el puntero de caracteres que apunta a la memoria" ... recuerde que algunos compiladores pueden no permitir esto ... Aquí está la demostración
fuente
Como esto puede diferir de un compilador a otro, la mejor manera es filtrar un volcado de objeto para el literal de cadena buscado:
donde
-s
obligaobjdump
a mostrar el contenido completo de todas las secciones,main.o
es el archivo objeto,-B 1
obligagrep
a imprimir también una línea antes de la coincidencia (para que pueda ver el nombre de la sección) ystr
es el literal de cadena que está buscando.Con gcc en una máquina con Windows, y una variable declarada en
main
likecorriendo
devoluciones
fuente