segmento - segmentacion de memoria
¿Cómo se relacionan los diferentes segmentos como montón, pila, texto en la memoria física? (6)
4. Si observa un código de ensamblador generado por gcc, puede ver que las variables locales de la memoria se asignan en la pila mediante el comando push
o mediante el cambio del valor del registro ESP
. Luego se inician con el comando mov
o algo así.
Cuando se compila un programa en C y se crea el archivo objeto (ELF). El archivo objeto contiene diferentes secciones como bss, datos, texto y otros segmentos. Comprendí que estas secciones de ELF forman parte del espacio de direcciones de la memoria virtual. Estoy en lo cierto? Por favor, corríjame si estoy equivocado.
Además, habrá una memoria virtual y una tabla de páginas asociadas con el programa compilado. La tabla de páginas asocia la dirección de memoria virtual presente en ELF a la dirección de memoria física real cuando se carga el programa. ¿Mi entendimiento es correcto?
Leí que en el archivo ELF creado, las secciones bss solo mantienen la referencia de las variables globales sin inicializar. ¿Aquí, variable global no inicializada significa las variables que no se inicializan durante la declaración?
Además, leí que a las variables locales se les asignará espacio en el tiempo de ejecución (es decir, en la pila). Entonces, ¿cómo serán referenciados en el archivo objeto?
Si está en el programa, hay una sección particular de código disponible para asignar memoria dinámicamente. ¿Cómo se hará referencia a estas variables en el archivo objeto?
Estoy confundido de que estos diferentes segmentos de archivo de objeto (como texto, rodata, datos, bss, pila y montón) son parte de la memoria física (RAM), donde se ejecutan todos los programas. Pero siento que mi entendimiento es incorrecto. ¿Cómo se relacionan estos diferentes segmentos con la memoria física cuando se ejecuta un proceso o un programa?
No estoy seguro de si 1, 2 y 3 son correctos, pero puedo explicar 4 y 5.
4 : Están referenciados por desplazamiento desde la parte superior de la pila. Al ejecutar una función, la parte superior de la pila se incrementa para asignar espacio para las variables locales. El compilador determina el orden de las variables locales en la pila para que el compilador sepa cuál es el desplazamiento de las variables desde la parte superior de la pila.
La pila en la memoria física se coloca boca abajo. El comienzo de la pila generalmente tiene la dirección de memoria más alta disponible. A medida que los programas se ejecutan y asignan espacio para las variables locales, la dirección de la parte superior de la pila disminuye (y puede potencialmente provocar un desbordamiento de la pila, superponiéndose con los segmentos en las direcciones inferiores :-))
5 : Uso de punteros: la dirección de la variable asignada dinámicamente se almacena en la variable (local). Esto corresponde a usar punteros en C.
He encontrado una buena explicación aquí: http://www.ualberta.ca/CNS/RESEARCH/LinuxClusters/mem.html
Si desea saber estas cosas, aprenda sobre el sistema operativo, con el código fuente (www.kernel.org) si es posible.
Debe darse cuenta de que el núcleo del sistema operativo en realidad está ejecutando la CPU y administrando el recurso de memoria. Y el código C es solo un script liviano para manejar el sistema operativo y para ejecutar solo operaciones simples con registros.
La memoria virtual y la memoria física tratan sobre el TLB de la CPU, lo que permite que el proceso del usuario utilice la memoria contigua virtualmente a través de la potencia del hardware TLB (mediante la tabla de páginas). Por lo tanto, la memoria física real, asignada a la memoria virtual contigua, se puede dispersar a cualquier lugar en la RAM. El programa compilado no sabe sobre estas cosas de TLB y cosas de dirección de memoria física. Se gestionan en el espacio kernel del sistema operativo.
BSS es una sección que el sistema operativo prepara como direcciones de memoria con cero rellenos, ya que no fueron inicializadas en el código fuente de c / c ++, por lo que el compilador / vinculador las marcó como bss.
La pila es algo preparado, solo una pequeña cantidad de memoria al principio por el sistema operativo, y cada vez que se realiza una llamada de función, la dirección se empuja hacia abajo, de modo que hay más espacio para colocar las variables locales, y se abre cuando se desea volver de la función. La nueva memoria física se asignará a la dirección virtual cuando la primera pequeña cantidad de memoria esté llena y llegue a la parte inferior, y se producirá una excepción de error de página, y el kernel del sistema operativo preparará una nueva memoria física y el proceso del usuario podrá continuar trabajando.
No hay magia. En el código objeto, cada operación realizada al puntero devuelto desde malloc se maneja como compensaciones al valor de registro devuelto por la llamada a la función malloc.
En realidad malloc está haciendo cosas bastante complejas. Existen varias implementaciones (jemalloc / ptmalloc / dlmalloc / googlemalloc / ...) para mejorar las asignaciones dinámicas, pero en realidad todas obtienen una nueva región de memoria del sistema operativo utilizando sbrk o mmap (/ dev / zero), que se llama memoria anónima .
Simplemente haga un comando de lectura para averiguar las direcciones de inicio de los diferentes segmentos de su programa.
Respecto a la primera pregunta tienes toda la razón. Dado que la mayoría de los sistemas actuales utilizan el enlace en tiempo de ejecución, solo durante la ejecución se conocen las direcciones físicas reales. Además, es el compilador y el cargador los que dividen el programa en diferentes segmentos después de vincular las diferentes bibliotecas durante el tiempo de compilación y carga. De ahí, las direcciones virtuales.
Llegando a la segunda pregunta, es en tiempo de ejecución debido al enlace en tiempo de ejecución. La tercera pregunta es cierta. Todas las variables globales no inicializadas y las variables estáticas entran en BSS. También tenga en cuenta el caso especial: entran en BSS incluso si se inicializan a 0.
Todas las direcciones de las diferentes secciones (.text, .bss, .data, etc.) que ve cuando inspecciona un ELF con el comando de tamaño:
$ size -A -x my_elf_binary
Son direcciones virtuales. La MMU con el sistema operativo realiza la traducción de las direcciones virtuales a las direcciones físicas de RAM.
1. Correcto, el archivo ELF establece las ubicaciones absolutas o relativas en el espacio de direcciones virtuales de un proceso en el que el sistema operativo debería copiar el contenido del archivo ELF. (El bss es solo una ubicación y un tamaño, ya que se supone que son todos ceros, no es necesario tener los ceros en el archivo ELF). Tenga en cuenta que las ubicaciones pueden ser ubicaciones absolutas (como la dirección virtual 0x100000 o ubicaciones relativas como 4096 bytes después del final del texto).
2. La definición de memoria virtual (que se mantiene en las tablas de páginas y asigna direcciones virtuales a direcciones físicas) no está asociada con un programa compilado, sino con un "proceso" (o "tarea" o lo que sea que su sistema operativo le llame) que representa un Ejecución de la instancia de ese programa. Por ejemplo, un solo archivo ELF se puede cargar en dos procesos diferentes, en diferentes direcciones virtuales (si el archivo ELF es reubicable).
3. El lenguaje de programación que está utilizando define qué estado no inicializado pasa en bss y cuál se inicializa explícitamente. Tenga en cuenta que el bss no contiene "referencias" a estas variables, es el almacenamiento que las respalda.
4. Las variables de la pila están referenciadas implícitamente desde el código generado. No hay nada explícito sobre ellos (o incluso la pila) en el archivo ELF.
5. Al igual que las referencias de pila, las referencias de pila están implícitas en el código generado en el archivo ELF. (Todos se almacenan en la memoria creada al cambiar el espacio de direcciones virtuales a través de una llamada a sbrk
o su equivalente).
El archivo ELF explica a un sistema operativo cómo configurar un espacio de direcciones virtuales para una instancia de un programa. Las diferentes secciones describen diferentes necesidades. Por ejemplo, ".rodata" dice que me gustaría almacenar datos de solo lectura (a diferencia del código ejecutable). La sección ".text" significa código ejecutable. El "bss" es una región utilizada para almacenar el estado que el sistema operativo debe poner a cero. El espacio de direcciones virtuales significa que el programa puede (opcionalmente) confiar en que las cosas estén donde espera cuando se inicie. (Por ejemplo, si solicita que .bss esté en la dirección 0x4000, entonces el sistema operativo se negará a iniciarlo o estará allí).
Tenga en cuenta que estas direcciones virtuales se asignan a direcciones físicas mediante las tablas de páginas administradas por el sistema operativo. La instancia del archivo ELF no necesita conocer ninguno de los detalles involucrados en las páginas físicas que se utilizan.