¿Cuál es el propósito de la zona roja?

12

La zona roja es un área de tamaño fijo en la memoria más allá del puntero de la pila que no se ha "asignado". Los compiladores generan ensamblados para acceder a esa área en simples funciones de hoja.

Pero no puedo ver ninguna ventaja real para la zona roja. Acceder a la memoria más allá del puntero de la pila es realmente peligroso y puede conducir fácilmente a la corrupción de datos . ¿Por qué incluso hacer esto? Guardar 2 instrucciones del procesador (push ebp; mov ebp esp) no dará una velocidad real.

Alexander Dzyoba
fuente

Respuestas:

16

La zona roja es, pura y simplemente, una optimización que puede guardar instrucciones. Significa que ya no es necesario que el código emitido para cada función se reste del puntero de la pila para hacer el almacenamiento local de esta manera

sub XXX, %rsp 

al comienzo de cada llamada de función, incluso si no son funciones de hoja. Muchas veces el código emitido por el compilador puede usar el espacio temporal en la zona roja debajo del puntero de la pila sin necesidad de guardarlo y antes de llamar a otras funciones. Esta es una optimización útil para tener disponible.

Si ya no tiene que sub desde el puntero de la pila, el código emitido puede usar rsp como puntero base, un trabajo normalmente reservado para rbp, y el código emitido puede usar rbp como otro registro de propósito general.

En última instancia, esto significa que el prólogo y el epílogo de cada llamada de función pueden guardar dos instrucciones que guardarían y restaurarían rbp:

(ensamblador de GNU)

pushq %rbp       # prologue [ two instructions not necessary ]
movq %rsp,%rbp

.... [code]

movq %rbp,%rsp   # epilogue [ two instructions not necessary ]
popq %rbp        

Tenga en cuenta que en gcc puede pasar el indicador -mno-red-zone si no lo desea (pero la ABI x86-64 lo requiere). El kernel de Linux no necesita ser compatible con ABI y, por lo tanto, todo el código del kernel se compila con -mno-red-zone.

Además, acceder a la memoria más allá del puntero de la pila no es peligroso si ese es el modo de operación esperado. Es solo peligroso y puede conducir a la corrupción cuando no es planeado e inesperado. Cuando el código emitido lo hace, sabe lo que está haciendo.

Brian Onn
fuente
Sí, entiendo esto. ¿Pero guardar 1 instrucción (sub de esp) es realmente una optimización? Me refiero a ahorrar pocos bytes y 1 ciclo de procesador por el precio de la posibilidad real de corromper los datos. ¿Quizás hay alguna otra razón para hacerlo?
Alexander Dzyoba
3
La optimización no es realmente el sub de esp, pero como ya no tienes que sub de esp, puedes usar esp como puntero base (normalmente hecho por ebp) y usar ebp para otra cosa en el código de función. Finalmente, debido a que esp es ahora el puntero base, el código puede evitar guardar y restaurar ebp en el prólogo / epílogo. Aclararé la respuesta con esta información adicional
Brian Onn,
edite y cambie a rbp / rsp en lugar de ebp / esp ya que la zona roja es solo una parte de la x86-64 ABI (aunque nada impide que uno use la misma técnica con registros de 32 bits; pero ningún compilador lo hace de esa manera hoy)
Brian Onn
1
La omisión del puntero de fotograma no está relacionada con la zona roja en absoluto: el compilador puede indexar la pila usando %rspcomo puntero base de cualquier manera.
alecov