Por que as pilhas geralmente crescem para baixo?

Eu sei que nas arquiteturas que eu estou pessoalmente familiarizado (x86, 6502, etc), a pilha normalmente cresce para baixo (ou seja, cada item empurrado para a pilha resulta em um SP decrementado, não um incremento).

Eu estou me perguntando sobre a lógica histórica para isso. Eu sei que em um espaço de endereço unificado, é conveniente iniciar a pilha na extremidade oposta do segmento de dados (digamos), então só há um problema se os dois lados colidirem no meio. Mas por que a pilha tradicionalmente obtém a parte superior? Especialmente considerando como isso é o oposto do modelo “conceitual”?

(E observe que na arquitetura do 6502, a pilha também cresce para baixo, embora seja limitada a uma única página de 256 bytes, e essa escolha de direção parece arbitrária.)

Quanto ao raciocínio histórico, não posso dizer com certeza (porque não os desenhei). Minha opinião sobre o assunto é que as primeiras CPUs tiveram seu contador de programa original definido como 0 e foi um desejo natural começar a pilha do outro lado e crescer para baixo, já que seu código cresce naturalmente para cima.

Como um aparte, note que esta configuração do contador de programa para 0 na reboot não é o caso para todas as CPUs iniciais. Por exemplo, o Motorola 6809 0xfffe/f o contador de programa dos endereços 0xfffe/f para que você pudesse começar a executar em um local arbitrário, dependendo do que foi fornecido naquele endereço (normalmente, mas não limitado a, ROM).

Uma das primeiras coisas que alguns sistemas históricos fariam seria escanear a memory do topo até encontrar um local que pudesse ler o mesmo valor escrito, para que ela pudesse saber a RAM real instalada (por exemplo, um z80 com espaço de endereço de 64K não tinha necessariamente 64K ou RAM, na verdade 64K teria sido massivo nos meus primeiros dias). Uma vez encontrado o endereço real de cima, ele definiria o ponteiro da pilha apropriadamente e poderia então começar a chamar sub-rotinas. Essa verificação geralmente seria feita pelo código de execução da CPU na ROM como parte da boot.

Com relação ao crescimento das pilhas, nem todas crescem para baixo, veja esta resposta para detalhes.

Uma boa explicação que eu ouvi foi que algumas máquinas no passado só podiam ter compensações não assinadas, então você iria querer que a pilha crescesse para baixo para que você pudesse atingir seus locais sem ter que perder a instrução extra para falsificar um offset negativo.

Um possível motivo pode ser que isso simplifique o alinhamento. Se você colocar uma variável local na pilha que deve ser colocada em um limite de 4 bytes, você pode simplesmente subtrair o tamanho do object do ponteiro da pilha e, em seguida, zerar os dois bits inferiores para obter um endereço adequadamente alinhado. Se a pilha crescer para cima, assegurando que o alinhamento fique um pouco mais complicado.

IIRC a pilha cresce para baixo porque a pilha cresce para cima. Poderia ter sido o contrário.

Eu acredito que é puramente uma decisão de design. Nem todos eles crescem para baixo – veja este tópico da SO para uma boa discussão sobre a direção do crescimento da pilha em diferentes arquiteturas.

Acredito que a convenção começou com o IBM 704 e seu infame “registro de decréscimo”. O discurso moderno o chamaria de um campo de deslocamento da instrução, mas o ponto é que eles caíram , não para cima .

Não tenho certeza, mas fiz algumas programações para o VAX / VMS nos dias de hoje. Eu pareço lembrar uma parte da memory (a pilha?) Subindo e a pilha caindo. Quando os dois se conheceram, você estava sem memory.

Apenas mais 2c:

Além de todas as razões históricas mencionadas, tenho certeza de que não há razão válida nos processadores modernos. Todos os processadores podem ter offsets assinados, e maximizar a distância do heap / stack é bastante discutível desde que começamos a lidar com vários threads.

Eu pessoalmente considero isso uma falha no design de segurança. Se, por exemplo, os projetistas da arquitetura x64 tivessem invertido a direção de crescimento da pilha, os overflows de buffer de pilha teriam sido eliminados – o que é meio que um grande problema.