La dirección de memoria estática int arr [10] siempre termina en 060

17

Tengo un programa de CA que se ve así

C Principal

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

y genera esto cuando ejecuto el programa compilado varias veces

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

¿Por qué siempre termina en 060? ¿Y la matriz está almacenada en el montón?

Editar: estoy en Linux y tengo ASLR. Compilé el programa usando gcc

linuxlmao
fuente
2
Que sistema operativo Que compilador
Andrew Henle
2
La variable no está en el montón, está en la sección de datos o bss del espacio de direcciones del programa, consulte en.wikipedia.org/wiki/Static_variable . Supongo que el programa siempre se colocará en una dirección de memoria en un límite determinado, por ejemplo, divisible por 0x1000, y el compilador coloca la variable en un desplazamiento fijo en el espacio de direcciones del programa.
Bodo

Respuestas:

15

Las direcciones difieren debido a ASLR (ramdomización del diseño del espacio de direcciones). Con esto, el binario se puede mapear en diferentes ubicaciones en el espacio de direcciones virtuales.

La variable heapes, en contraste con su nombre, no se encuentra en el montón, sino en el bss. El desplazamiento en el espacio de direcciones es, por lo tanto, constante.

Las páginas se asignan a la granularidad de la página, que es 4096 bytes (hexadecimal: 0x1000) en muchas plataformas. Esta es la razón por la cual los últimos tres dígitos hexadecimales de la dirección son los mismos.

Cuando hizo lo mismo con una variable de pila , la dirección podría incluso variar en los últimos dígitos en algunas plataformas (es decir, Linux con núcleos recientes), porque la pila no solo está asignada en otro lugar sino que también recibe un desplazamiento aleatorio al inicio.

Ctx
fuente
ASLR aleatoriza la base de carga como recuerdo. La dirección de la sección se basa en esa dirección.
Afshin
Estoy usando un libro sobre programación ANSI-C orientada a objetos de Axel-Thobias Schreiner. El libro está escrito en algo así como 1993. ¿Sabes si el diseño de la memoria era diferente en ese entonces? Si no fuera así, ¿por qué podría haber nombrado la variable heapcuando no está en el montón?
linuxlmao
¿4096 se traduce a 060 de alguna manera o 0x1000 se traduce a 060 de lo contrario no entiendo lo que quieres decir con que ese es el motivo del final? Pensé que podría tener que ver con que el tamaño de la matriz es algo que se traduce a 060 en hexadecimal, por ejemplo, decimal
linuxlmao
2
@linuxlmao El desplazamiento es, por ejemplo, 14060, por lo que cuando agrega un múltiplo de un tamaño de página (0x1000), quedan los últimos tres dígitos 060.
Ctx
4

Si está utilizando Windows, la razón es la estructura PE .

Su heapvariable se almacena en la .datasección del archivo y su dirección se calcula en función del inicio de esta sección. Cada sección se carga en una dirección de forma independiente, pero su dirección inicial es múltiple del tamaño de la página. Debido a que no tiene otras variables, es probable que su dirección sea el inicio de la .datasección, por lo que su dirección será múltiplo del tamaño del fragmento.

Por ejemplo, esta es la tabla de la versión compilada de Windows de su código: secciones La .textsección es donde su código compilado es y .datacontiene su heapvariable. Cuando su PE se carga en la memoria, las secciones se cargan en una dirección diferente y la devuelve VirtualAlloc()y será múltiplo del tamaño de la página. Pero la dirección de cada variable es relativa al inicio de la sección que ahora es un tamaño de página. Por lo tanto, siempre verá un número fijo en los dígitos más bajos. Dado que la dirección relativa de heapdesde el inicio de la sección se basa en el compilador, las opciones de compilación, etc., verá un número diferente del mismo código, pero diferentes compiladores, pero cada vez que se imprima se corrige.

Cuando compilo código, noté que heapse coloca en 0x8B0bytes después del inicio de la .datasección. Entonces, cada vez que ejecuto este código, mi dirección termina en 0x8B0.

Afshin
fuente
Estoy usando un libro sobre programación ANSI-C orientada a objetos de Axel-Thobias Schreiner. El libro está escrito en algo así como 1993. ¿Sabes si el diseño de la memoria era diferente en ese entonces? Si no fuera así, ¿por qué podría haber nombrado la variable heapcuando no está en el montón?
linuxlmao
2
@linuxlmao Bien pudo haber sido diferente. En 1993, Windows era un sistema operativo de 16 bits, con segmentación de memoria y todo tipo de cosas confusas. Era no una, la arquitectura de memoria plana de 32 bits como lo es ahora. Pero este tipo de cosas son las razones por las que hacer / responder preguntas generales sobre el diseño de un programa binario en la memoria no es útil. Comprenda lo que el estándar del lenguaje C le garantiza en general , y eso es todo lo que necesita saber. Solo preocúpese por el diseño real si está depurando un problema específico, luego use un depurador
Cody Gray
no, la variable no debe crearse en el montón incluso en sistemas más antiguos porque no se asignó con malloc y tiene una duración de almacenamiento estático
phuclv
@Afshin Me dirijo al comentario del OP anterior
phuclv
@phuclv lo siento, porque no lo mencionaste, pensé que te dirigías a mí. :)
Afshin
4

El compilador pasó a colocar heap0x60 bytes en un segmento de datos que tiene, posiblemente porque el compilador tiene otras cosas en los primeros 0x60 bytes, como los datos utilizados por el código que inicia la mainrutina. Por eso ves "060"; es justo donde estaba, y no tiene gran importancia.

La aleatorización del diseño del espacio de direcciones cambia las direcciones base utilizadas para varias partes de la memoria del programa, pero siempre lo hace en unidades de 0x1000 bytes (porque esto evita causar problemas con la alineación y otros problemas). Entonces verá que las direcciones fluctúan por múltiplos de 0x1000, pero los últimos tres dígitos no cambian.

La definición static int heap[SOME_VAR];define heapcon la duración del almacenamiento estático. Las implementaciones típicas de C lo almacenan en una sección de datos generales, no en el montón. El "montón" es un nombre inapropiado para la memoria que se utiliza para la asignación dinámica. (Es un nombre inapropiado porque las mallocimplementaciones pueden usar una variedad de estructuras de datos y algoritmos, no limitados a montones. Incluso pueden usar múltiples métodos en una implementación).

Eric Postpischil
fuente