GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo funciona la asignación de pila en Linux?

Parece que el límite de memoria de la pila no está asignado (de todos modos, no podría con una pila ilimitada). https://www.kernel.org/doc/Documentation/vm/overcommit-accounting dice:

El crecimiento de la pila del lenguaje C hace un mremap implícito. Si desea garantías absolutas y correr cerca del borde, DEBE mapear su pila para obtener el tamaño más grande que cree que necesitará. Para el uso típico de la pila, esto no importa mucho, pero es un caso de esquina si realmente te importa

Sin embargo, mapear la pila sería el objetivo de un compilador (si tiene una opción para eso).

EDITAR:después de algunas pruebas en una máquina Debian x84_64, descubrí que la pila crece sin ninguna llamada al sistema (según strace ). Entonces, esto significa que el kernel lo hace crecer automáticamente (esto es lo que significa "implícito" arriba), es decir, sin mmap explícito /mremap del proceso.

Fue bastante difícil encontrar información detallada que confirmara esto. Recomiendo Comprender el administrador de memoria virtual de Linux por Mel Gorman. Supongo que la respuesta está en la Sección 4.6.1 Manejo de un error de página , con la excepción "La región no es válida pero está al lado de una región expandible como la pila" y la acción correspondiente "Expandir la región y asignar una página". Consulte también D.5.2 Expandir la pila .

Otras referencias sobre gestión de memoria Linux (pero sin casi nada sobre la pila):

  • Preguntas frecuentes sobre la memoria
  • Lo que todo programador debe saber sobre la memoria por Ulrich Drepper

EDICIÓN 2:esta implementación tiene un inconveniente:en los casos de esquina, es posible que no se detecte una colisión pila-montón, ¡incluso en el caso de que la pila sea más grande que el límite! La razón es que una escritura en una variable en la pila puede terminar en la memoria del montón asignada, en cuyo caso no hay falla de página y el núcleo no puede saber que la pila necesita ser extendida. Vea mi ejemplo en la discusión Silent stack-heap colision bajo GNU/Linux que comencé en la lista de ayuda de gcc. Para evitar eso, el compilador necesita agregar algo de código en la llamada a la función; esto se puede hacer con -fstack-check para GCC (consulte la respuesta de Ian Lance Taylor y la página del manual de GCC para obtener más detalles).


Núcleo de Linux 4.2

  • mm/mmap.c#acct_stack_growth decide si fallará o no. Utiliza rlim[RLIMIT_STACK] que corresponde al POSIX gerlimit(RLIMIT_STACK)
  • arch/x86/mm/fault.c#do_page_fault es el controlador de interrupciones que inicia una cadena que termina llamando a acct_stack_growth
  • arch/x86/entry/entry_64.S configura el controlador de errores de página. Necesita saber un poco sobre la paginación para entender esa parte:¿Cómo funciona la paginación x86? | Desbordamiento de pila

Programa de prueba mínimo

Luego podemos probarlo con un programa mínimo de NASM de 64 bits:

global _start
_start:
    sub rsp, 0x7FF000
    mov [rsp], rax
    mov rax, 60
    mov rdi, 0
    syscall

Asegúrese de desactivar ASLR y eliminar las variables de entorno, ya que se colocarán en la pila y ocuparán espacio:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
env -i ./main.out

El límite está ligeramente por debajo de mi ulimit -s (8MiB para mí). Parece que esto se debe a los datos adicionales especificados de System V que se colocaron inicialmente en la pila además del entorno:parámetros de línea de comando de Linux 64 en Ensamblaje | Desbordamiento de pila

Si te tomas en serio esto, TODO crea una imagen initrd mínima que comience a escribir desde la parte superior de la pila y se vaya hacia abajo, y luego ejecútala con QEMU + GDB. Pon un dprintf en el bucle imprimiendo la dirección de la pila y un punto de interrupción en acct_stack_growth . Será glorioso.

Relacionado:

  • https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
  • ¿De dónde se asigna la memoria de pila para un proceso de Linux? | Desbordamiento de pila
  • ¿Qué es la pila de Linux? | Desbordamiento de pila
  • ¿Cuál es la profundidad de recursión máxima en Python y cómo aumentarla? en el desbordamiento de pila

De forma predeterminada, el tamaño de pila máximo está configurado para ser de 8 MB por proceso,
pero se puede cambiar usando ulimit :

Mostrando el valor predeterminado en kB:

$ ulimit -s
8192

Establecer en ilimitado:

ulimit -s unlimited

afectando el shell actual y los subshells y sus procesos secundarios.
(ulimit es un comando integrado de shell)

Puede mostrar el rango de direcciones de la pila real en uso con:
cat /proc/$PID/maps | grep -F '[stack]'
en Linux.


Linux
  1. Cómo borrar la caché de memoria en Linux

  2. Linux:¿cómo funciona el promedio de carga con las CPU modernas?

  3. ¿La asignación de memoria en Linux no bloquea?

  4. ¿Cómo funciona internamente copy_from_user del kernel de Linux?

  5. ZFS bajo Linux, ¿funciona?

Cómo deshabilitar permanentemente el intercambio en Linux

Linux:¿cómo funciona la pantalla de Linux?

¿Qué es el comando fuente en Linux y cómo funciona?

¿Cómo funciona el intercambio de memoria en Linux?

¿Cómo funciona una GUI de Linux en el nivel más bajo?

¿Cómo funciona la pantalla de Linux?