¿Por qué se llena la pila de las direcciones más altas a las más bajas? ¿Podría un diseño de pila diferente evitar sobrescribir el puntero de retorno de pila?

¿Por qué se llena la pila de las direcciones más altas a las más bajas?

Porque la mayoría de las CPU lo quieren así.

La dirección del crecimiento de la pila está determinada principalmente por las instrucciones de manipulación de la pila de CPU disponibles. Algunos conjuntos de instrucciones (por ejemplo, el omnipresente x86 de Intel) tienen instrucciones PUSH y POP dedicadas con una dirección de crecimiento codificada, mientras que otros (por ejemplo, la familia 68K de Motorola) manipulan el puntero de la pila directamente.

Para este último, los modos de direccionamiento de incremento y decremento incorporados en el conjunto de instrucciones a menudo influyeron directamente en la dirección de crecimiento de la pila, ya que formarían la base de PUSH y POP de la siguiente manera:

  • PUSH = modo “pre” (“mueve el puntero de la pila, luego escribe un nuevo valor donde está apuntando”)
  • POP = modo “post-” (“devolver el valor en el puntero de la pila, luego mover el puntero”)

Por ejemplo, la familia 68K lucía modos de incremento posterior y decremento previo, por lo que el crecimiento de la pila hacia abajo era más lógico, mientras que uno con modos de incremento previo y decremento favorecería las pilas de crecimiento ascendente. (Creo que la arquitectura ARM puede ir en ambos sentidos. [1])

Históricamente, ha habido un sesgo en casi todas las CPU hacia pilas de crecimiento descendente, aunque algunas crecieron hacia arriba (por ejemplo, PDP-10 de DEC [2]), y la familia de CPU SPARC incluso le permitió decidir por sí mismo, al pasar un positivo o compensación negativa a sus instrucciones SAVE / RESTORE. Sun Microsystems simplemente eligió “crecer hacia abajo” para su Solaris ABI (interfaz binaria de aplicación).

(Por cierto, DEC también es el único fabricante que conozco que ha cambiado de opinión sobre este asunto, cambiando a “crecer” para el PDP-11 [3]. Mejor aún, la serie KL de PDP-10 usaba PDP-11 como sus procesadores frontend, lo que resulta en los únicos sistemas informáticos en la historia cuyas pilas posiblemente crecieron en ambas direcciones! [4])

¿Podría un diseño de pila diferente evitar sobrescribir el puntero de retorno de pila?

Dada la práctica ahora común de almacenar variables locales en la pila, una forma en la que puedo pensar para evitar esto es:

  • restringir el uso de la pila para devolver punteros (es decir, almacenar locales en otro lugar) y
  • restringir el acceso directo al contenido de la pila.

La primera no es una idea nueva: FORTH ha mantenido históricamente datos separados (“locales”) y pilas de devoluciones. El segundo es bastante complicado, y no afirmaré saber cómo lograr esta combinación; creo que los cambios de ABI serían bastante extensos.

Notas al pie

[1] http: // ftp: //www.cs.uregina.ca/p…

[2] Pila PDP-10

[3] Arquitectura PDP-11 – Wikipedia

[4] PDP-10 – Wikipedia

La disposición habitual es tener el código y los datos constantes asignados desde el comienzo del espacio de direcciones, seguido de un grupo de memoria asignada dinámicamente (el montón). Si ese es el caso, tiene sentido asignar la pila desde el otro extremo, es decir, la dirección virtual más alta, y crecer en la dirección opuesta.