architecture - sheet - queue first
¿Por qué las pilas normalmente crecen hacia abajo? (8)
Creo que es puramente una decisión de diseño. No todos crecen a la baja: consulte este hilo SO para tener una buena discusión sobre la dirección del crecimiento de la pila en diferentes arquitecturas.
Sé que en las arquitecturas con las que estoy familiarizado (x86, 6502, etc.), la pila normalmente crece hacia abajo (es decir, cada elemento insertado en la pila da como resultado un SP decrementado, no uno incrementado).
Me pregunto sobre la razón histórica para esto. Sé que en un espacio de dirección unificado, es conveniente comenzar la pila en el extremo opuesto del segmento de datos (por ejemplo), por lo que solo hay un problema si los dos lados colisionan en el medio. ¿Pero por qué la pila tradicionalmente obtiene la parte superior? ¿Especialmente dado que esto es lo opuesto al modelo "conceptual"?
(Y tenga en cuenta que en la arquitectura 6502, la pila también crece hacia abajo, aunque está limitada a una única página de 256 bytes, y esta elección de dirección parece arbitraria).
Creo que la convención comenzó con el IBM 704 y su infame "decrement register". El habla moderna lo llamaría un campo de desplazamiento de la instrucción, pero el punto es que bajaron , no subieron .
En cuanto a la lógica histórica, no puedo decirlo con certeza (porque no los diseñé). Mi opinión al respecto es que los primeros CPUs tenían su contador de programa original configurado en 0 y era un deseo natural comenzar la pila en el otro extremo y crecer hacia abajo, ya que su código crece naturalmente hacia arriba.
Como un aparte, tenga en cuenta que esta configuración del contador de programa a 0 en el reinicio no es el caso para todas las CPUs tempranas. Por ejemplo, el Motorola 6809
0xfffe/f
contador del programa desde las direcciones0xfffe/f
para que pueda comenzar a ejecutar en una ubicación arbitraria, dependiendo de lo que se suministró en esa dirección (generalmente, pero de ninguna manera limitada, a la ROM).
Una de las primeras cosas que harían algunos sistemas históricos sería escanear la memoria desde la parte superior hasta que encontrara una ubicación que leyera el mismo valor escrito, para que supiera la RAM real instalada (por ejemplo, un z80 con espacio de direcciones de 64K) no necesariamente tenía 64K o RAM, de hecho 64K habría sido masivo en mis primeros días). Una vez que encuentre la dirección real superior, establecerá el puntero de la pila de manera apropiada y luego podrá comenzar a llamar a las subrutinas. Este escaneo generalmente lo haría el código de ejecución de la CPU en la ROM como parte de la puesta en marcha.
Con respecto al crecimiento de las pilas, no todas crecen hacia abajo, vea esta respuesta para más detalles.
IIRC la pila crece hacia abajo porque el montón crece hacia arriba. Podría haber sido al revés.
No estoy seguro pero hice algo de programación para el VAX / VMS en los días. Me parece recordar una parte de la memoria (¿el montón?) Que sube y la pila baja. Cuando los dos se conocieron, entonces estabas sin memoria.
Solo 2c más:
Más allá de todas las razones históricas mencionadas, estoy bastante seguro de que no hay ninguna razón válida en los procesadores modernos. Todos los procesadores pueden tomar compensaciones firmadas, y maximizar la distancia de pila / pila es bastante discutible desde que comenzamos a tratar con múltiples hilos.
Personalmente, considero esto un defecto de diseño de seguridad. Si, digamos, los diseñadores de la arquitectura x64 hubieran invertido la dirección de crecimiento de la pila, se hubieran eliminado los desbordamientos de la memoria tampón de la pila, lo cual es una gran cosa.
Una buena explicación que escuché fue que algunas máquinas en el pasado solo podían tener compensaciones sin firmar, por lo que querría que la pila creciera hacia abajo para poder golpear a los locales sin tener que perder las instrucciones adicionales para falsificar una compensación negativa.
Una posible razón podría ser que simplifica la alineación. Si coloca una variable local en la pila que debe colocarse en un límite de 4 bytes, simplemente puede restar el tamaño del objeto del puntero de pila y luego poner a cero los dos bits inferiores para obtener una dirección alineada correctamente. Si la pila crece hacia arriba, garantizar la alineación se vuelve un poco más complicado.