2010-01-10 13 views
75

Sé que en las arquitecturas con las que estoy familiarizado (x86, 6502, etc.), la pila generalmente crece hacia abajo (es decir, cada elemento insertado en la pila da como resultado un SP decrementado, no uno incrementado).¿Por qué las pilas normalmente crecen hacia abajo?

Me pregunto acerca de 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 de 6502, la pila también crece hacia abajo, a pesar de que está limitada a una sola página de 256 bytes, y esta elección dirección parece arbitrario.)

Respuesta

36

En cuanto a la lógica histórica, no puedo decirlo con certeza (porque no los diseñé). Mis pensamientos al respecto son que los primeros CPUs tenían su contador de programa original establecido 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 acotación al margen, tenga en cuenta que este ajuste del contador de programa a 0 en el restablecimiento no es el caso para todos los CPU tempranas. Por ejemplo, el Motorola 6809 buscará el contador del programa desde las direcciones 0xfffe/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 algunos sistemas históricos harían sería escanear la memoria desde la parte superior hasta que encontrara una ubicación que pudiera leer 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, ver this answer para más detalles.

+1

Me gusta la historia de estrategia de detección de Z80 RAM. Tiene sentido que los segmentos de texto se desarrollen hacia arriba, los programadores de antaño tenían un contacto un tanto más directo al tratar con las implicaciones de eso que la pila. Gracias paxdiablo. El puntero al conjunto de formas alternativas de implementaciones de pila también es muy interesante. –

+0

¿La memoria de los primeros días no tiene forma de notificar su tamaño y tenemos que calcularla manualmente? –

+1

@ LưuVĩnhPhúc, tengo que asumir que eres una generación (o dos) detrás de mí. Aún recuerdo el método TRS-80 modelo 3 para obtener la fecha y la hora para * preguntarle al usuario * en el momento del arranque. Tener un escáner de memoria para establecer el límite superior de la memoria se consideró de última generación en el día :-) ¿Te imaginas lo que sucedería si Windows preguntase la hora o la cantidad de memoria que tenías cada vez que arrancabas? – paxdiablo

3

IIRC la pila crece hacia abajo, porque el montón crece hacia arriba Podría haber sido al revés.

+3

Un montón que crece hacia arriba permite un realloc eficiente en algunos casos, pero un montón que crece hacia abajo casi nunca lo hace. –

15

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 un negativo compensar.

4

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.

+1

Las computadoras no restan; añaden el cumplido de 2. Todo lo que se hace restando se hace añadiendo. Considere, las computadoras tienen sumadores, no subtratistas. – jww

2

Creo que es puramente una decisión de diseño. No todos crecen a la baja; consulte this SO thread para tener una buena discusión sobre la dirección del crecimiento de la pila en diferentes arquitecturas.

0

No estoy seguro pero hice algo de programación para el VAX/VMS en el pasado. 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.

+1

Esto es cierto, pero ¿por qué el montón crece hacia arriba y no al revés? –

1

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 fueron abajo, nohasta.

0

Sólo más 2c:

Más allá de toda la razón histórica se ha mencionado, estoy bastante seguro de que no hay razón que es válido 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.

Cuestiones relacionadas