O que significa para uma CPU suportar uma pilha?

11

Como uma CPU não suporta uma pilha? Alguma arquitetura que usa sub-rotinas (tenho certeza de que são todas as arquiteturas) precisa inserir o endereço de retorno na pilha para que possa retornar para onde chamou a sub-rotina? A pilha significa apenas uma seção da memória com um ponteiro que cresce em uma determinada direção e atua como uma estrutura de dados da pilha, não? Só não entendo como uma arquitetura não suporta uma pilha.

Até que ponto o armazenamento automático de memória (variáveis ​​automáticas versus variáveis ​​estáticas) é determinado pelo compilador versus a arquitetura de hardware?

NickHalden
fonte

Respostas:

8

Existem muitos microcontroladores de baixo nível que possuem pilhas de hardware para chamada / retorno de sub-rotina e manipulação de interrupções, mas dificultam, se não impossível, o armazenamento de dados (variáveis) lá, e a implementação de uma pilha de dados puramente de software seria terrivelmente ineficiente. O 8051 é um exemplo clássico e os PICs low-end (PIC12 / PIC16) são outro. Nessas máquinas, a pilha de dados é emulada atribuindo locais de armazenamento estático para variáveis ​​automáticas, com a quantidade de reutilização desses locais dependente da sofisticação do compilador.

Observe que se a emulação de pilha estiver sendo feita dessa maneira, isso significa que a recursão - uma função que se chama direta ou indiretamente - não funciona, pois cada instância da função reutiliza os mesmos locais estáticos para suas variáveis ​​supostamente "privadas". Alguns compiladores permitem o uso limitado de recursão (normalmente implementado por meio de #pragmaalgum tipo), o que fará com que ele crie uma pilha de dados verdadeira, não importa o quanto isso lentifique.

Apenas como um aparte, houve arquiteturas de CPU que não tinham uma pilha de hardware, nem mesmo para manipulação de sub-rotina / interrupção, incluindo o DEC PDP-8 e o IBM System / 360. Nessas máquinas, o PC (endereço de retorno) e o registro de status (para interrupções) foram salvos em registradores ou locais de memória, mas em todos os casos em que posso pensar, a máquina também tinha modos de endereço suficientemente flexíveis que facilitavam a criação de uma pilha com software.

Dave Tweed
fonte
1
Alguns computadores anteriores escreviam uma instrução de salto no código para causar um retorno - sem saltos indiretos - tornando impraticáveis ​​as funções de reentrada (teoricamente, pode-se ramificar sobre um salto, mas isso aumenta a complexidade, em alguns casos, especialmente quando os endereços de dados são completamente codificados nas instruções).
Paul A. Clayton
4

"apoiar uma pilha" significa

  1. ter um registrador explícito de ponteiro de pilha e
  2. tendo instruções de código de máquina primitivas para manipular / usar o registro de ponteiro de pilha (como reti, que altera o contador do programa com base no ponteiro de pilha para retornar de uma chamada de função).

Você pode emular isso sem o suporte de hardware por meio da emulação, que é um código gerado pelo compilador com o mesmo tipo de coisas na RAM usando variáveis. É raro / incomum não ter suporte direto à pilha em nenhuma arquitetura moderna de computador.

A semântica de variáveis ​​nas linguagens de programação não tem quase nada a ver com a arquitetura de hardware de destino, para qualquer linguagem superior à montagem direta. O trabalho dos compiladores é gerar código de máquina compatível com o contrato semântico da linguagem de programação.

vicatcu
fonte
1
A maioria dos ISAs RISC (por exemplo, MIPS [excluindo MIPS16 e microMIPS], Alpha, SPARC, PA-RISC, Power, SuperH) não possui um registro de ponteiro de pilha explícito, definindo-o na ABI. O ARM é uma exceção (parcialmente porque obscurece o SP para vários modos de operação), assim como o MIP16 e o ​​microMIPS (para densidade de código).
Paul A. Clayton
2

Algumas arquiteturas (por exemplo, PIC) têm uma pilha de hardware com capacidade limitada (só pode ser usada para endereços de retorno, não variáveis). Algumas arquiteturas extremamente pequenas não têm uma instrução de armazenamento e incremento ou PUSH, portanto, é mais complicado fazer uma pilha.

variáveis ​​'auto' em C sempre devem ser compiladas para algo com comportamento de inicialização 'auto' e 'estático' com comportamento estático; em algumas arquiteturas, você não tem permissão para fazer recursão; nesse caso, o compilador pode alocar estaticamente todas as variáveis.

pjc50
fonte