sub rsp, <size>
para reservar espacio de pila antes de tocarlo, si está utilizando más de 128 bytes por debajo de RSP.
Cuando falla, mira tu mapa de memoria de proceso. Es posible que esté usando memoria tan por debajo de RSP que el núcleo no aumenta la asignación de pila y, por lo tanto, es solo un acceso normal a una página no asignada =falla de página no válida => el núcleo entrega SIGSEGV.
(La ABI solo define una zona roja de 128 bytes, pero en la práctica lo único que puede destruir esa memoria es un controlador de señal (que no instaló) o GDB que ejecuta print some_func()
usando la pila de su programa para llamar a una función en su programa.)
Normalmente, Linux está bastante dispuesto a hacer crecer el mapeo de la pila sin tocar las páginas intermedias, pero aparentemente verifica el valor de RSP. Normalmente mueves RSP en lugar de simplemente usar la memoria muy por debajo del puntero de la pila (porque no hay garantía de que sea seguro). Consulte ¿Cómo se asigna la memoria de pila cuando se usan instrucciones x86 'push' o 'sub'?
Otro duplicado:¿Qué excepción se puede generar al restar el registro ESP o RSP? (crecimiento de la pila) donde se usa sub rsp, 5555555
antes de tocar nueva memoria de pila fue suficiente.
Apilar ASLR podría iniciar RSP en diferentes lugares en relación con un límite de página , por lo que es posible que a veces apenas te salgas con la tuya. Linux asigna inicialmente 132 kiB de espacio de pila , y eso incluye espacio para el entorno y argumentos en la pila al ingresar a _start
. Tus 128 kiB están muy cerca de eso, por lo que es totalmente plausible que a veces funcione aleatoriamente.
Y, por cierto, no hay ninguna razón para copiar la memoria en el espacio del usuario, especialmente no 1 byte a la vez. Solo pasa la misma dirección a write
.
O al menos filtre en el lugar si es posible, para que su huella de caché sea más pequeña.
Además, la forma normal de cargar un byte es movzx eax, byte [mem]
. Solo usa mov al, [mem]
si desea fusionar específicamente con el antiguo valor de RAX. En algunas CPU, mov
a al
tiene una dependencia falsa en el valor anterior que puede romper escribiendo el registro completo.
Y, por cierto, si su programa siempre utiliza este espacio, también podría asignarlo estáticamente en el BSS. Eso hace posible un direccionamiento indexado más eficiente si elige ensamblar un ejecutable dependiente de la posición (no PIE).
La zona roja en amd64 tiene solo 128 bytes, pero está usando 131072 bytes por debajo de rsp. Mueva el puntero de la pila hacia abajo para abarcar los búferes que desea almacenar en la pila.