¿Qué significa que una CPU admita una pila?

¿Cómo puede una CPU no soportar una pila? ¿Alguna arquitectura que use subrutinas (estoy bastante seguro de que son todas las arquitecturas) no tiene que empujar la dirección de retorno a la pila para que pueda regresar a donde llamó a la subrutina? La pila solo significa una sección de memoria con un puntero que crece en cierta dirección y actúa como una estructura de datos de pila, ¿no? Simplemente no entiendo cómo una arquitectura no puede soportar una pila.

¿Hasta qué punto el almacenamiento de memoria automático (variables automáticas frente a variables estáticas) está determinado por el compilador frente a la arquitectura del hardware?

Respuestas (3)

Hay muchos microcontroladores de bajo nivel que tienen pilas de hardware para llamadas/retornos de subrutinas y manejo de interrupciones, pero hacen que sea difícil, si no imposible, almacenar datos (variables) allí, e implementar una pila de datos puramente de software sería terriblemente ineficiente. El 8051 es un ejemplo clásico y los PIC de gama baja (PIC12/PIC16) son otro. En estas máquinas, la pila de datos se emula mediante la asignación de ubicaciones de almacenamiento estáticas para variables automáticas, y la cantidad de reutilización de estas ubicaciones depende de la sofisticación del compilador.

Tenga en cuenta que si la emulación de pila se realiza de esta manera, significa que la recursividad, una función que se llama a sí misma, ya sea directa o indirectamente, no funciona, ya que cada instancia de la función reutiliza las mismas ubicaciones estáticas para sus variables supuestamente "privadas". Algunos compiladores permiten el uso limitado de la recursividad (típicamente implementada por medio de #pragmaalgún tipo), lo que hará que se cree una verdadera pila de datos sin importar cuánto ralentice las cosas.

Aparte, ha habido arquitecturas de CPU que no tenían una pila de hardware en absoluto, ni siquiera para el manejo de subrutinas/interrupciones, incluido el DEC PDP-8 y el IBM System/360. En estas máquinas, la PC (dirección de retorno) y el registro de estado (para interrupciones) se guardaron en registros o ubicaciones de memoria, pero en todos los casos que se me ocurren, la máquina también tenía modos de dirección suficientemente flexibles que facilitaban la creación de una pila. con programa

Algunas computadoras anteriores escribían una instrucción de salto en el código para provocar un retorno, sin saltos indirectos, lo que hacía que las funciones de reentrada fueran poco prácticas (teóricamente, uno podría bifurcarse en un salto, pero eso agrega complejidad, en algunos casos, especialmente cuando las direcciones de datos están completamente codificadas en las instrucciones).

"soportar una pila" significa

  1. tener un registro de puntero de pila explícito, y
  2. tener instrucciones de código de máquina primitivas para manipular / usar el registro del puntero de pila (como reti, que cambia el contador del programa en función del puntero de pila para regresar de una llamada de función).

Puede emular esto sin soporte de hardware a través de la emulación, que es un código generado por el compilador que hace el mismo tipo de cosas en la RAM usando variables. Es raro/poco común no tener soporte directo para la pila en cualquier arquitectura de computadora moderna.

La semántica de las variables en los lenguajes de programación no tiene casi nada que ver con la arquitectura de hardware de destino, para cualquier lenguaje superior al ensamblaje directo. El trabajo de los compiladores es generar un código de máquina que cumpla con el contrato semántico del lenguaje de programación.

La mayoría de los RISC ISA (p. ej., MIPS [excluyendo MIPS16 y microMIPS], Alpha, SPARC, PA-RISC, Power, SuperH) no tienen un registro de puntero de pila explícito, sino que lo definen en ABI. ARM es una excepción (en parte porque hace sombra al SP en varios modos operativos), al igual que MIP16 y microMIPS (para densidad de código).

Algunas arquitecturas (p. ej., PIC) tienen una pila de hardware con una capacidad limitada (solo se puede usar para direcciones de retorno, no para variables). Algunas arquitecturas extremadamente pequeñas no tienen una instrucción de almacenamiento e incremento o PUSH, por lo que es más complicado hacer una pila.

Las variables 'auto' en C siempre deben compilarse en algo con un comportamiento de inicialización 'auto' y 'static' con un comportamiento estático; en algunas arquitecturas no se le permite hacer recursividad, en cuyo caso el compilador puede asignar estáticamente todas las variables.